메인 메서드에서 첫 번째 주석 줄을 몇 번 실행하면 다음과 같은 예외 메시지가 표시됩니다. 동시 수정 예외, 우선 ArrayList는 스레드에 안전하지 않습니다. 이 예외가 발생하는 이유는 첫 번째 스레드가 추가 작업을 수행하기 위해 방금 ArrayList 컬렉션에 들어갔을 때 다른 스레드도 추가 작업을 수행하기 위해 들어왔기 때문입니다. 세 번째 스레드가 들어와서 가져오기 작업을 수행하면 읽기와 쓰기를 동기화할 수 없게 되고 결국 결과를 인쇄할 때 폭발하게 됩니다.
해결책은 코드의 나머지 주석 줄을 살펴보는 것입니다.
package test.notsafe; import java.util.*; import java.util.concurrent.CopyOnWriteArrayList; /** * 演示ArrayList的线程不安全问题及解决方案 */ public class ThreadDemo2 { public static void main(String[] args) { //List<String> list = new ArrayList<>(); //解决方法1:使用Vector //List<String> list = new Vector<>(); //解决方法2:Collections //List<String> list = Collections.synchronizedList(new ArrayList<>()); //解决方法3:CopyOnWriteArrayList List<String> list = new CopyOnWriteArrayList<>(); for (int i = 0; i < 10; i++) { new Thread(() -> { list.add(UUID.randomUUID().toString().substring(0,8)); System.out.println(list); },String.valueOf(i)).start(); } } }
CopyOnWriteArrayList가 스레드 보안 문제를 해결하는 방법에 대한 간단한 설명: 소스 코드의 add(E e) 메서드를 살펴보세요.
public boolean add(E e) { final ReentrantLock lock = this.lock; lock.lock(); try { Object[] elements = getArray(); int len = elements.length; Object[] newElements = Arrays.copyOf(elements, len + 1); newElements[len] = e; setArray(newElements); return true; } finally { lock.unlock(); } }
이 CopyOnWriteArrayList는 추가 작업을 수행하기 전에 먼저 잠그고 통과합니다. getArray()는 원본 ArrayList 컬렉션 컨테이너를 얻은 다음 Arrays.copyOf 메서드를 호출하여 원래 컨테이너를 새 컨테이너에 복사합니다. 왜냐하면 컨테이너를 추가해야 하기 때문입니다(길이는 당연히 +1이 됩니다). 그런 다음 여기에 요소를 추가합니다. 추가가 완료된 후 setArray 메소드를 호출하여 원래 컨테이너의 참조가 이 새 컨테이너를 가리키도록 합니다. 그러면 이 작업의 장점은 원래 컨테이너가 무엇이든 새 컨테이너에 요소를 추가하고 다른 스레드가 요소를 가져오고 읽으려는 경우 여전히 원래 컨테이너에서 읽습니다(즉, 여러 스레드가 동시에 읽을 수 있음). ; 그리고 다른 스레드가 추가하려면 다른 스레드가 완료될 때까지 기다린 다음 원래 컨테이너의 참조를 새 컨테이너로 지정해야 합니다.
CopyOnWrite 컨테이너는 읽기와 쓰기에 관한 두 가지 다른 컨테이너이며, 읽기와 쓰기를 분리하는 아이디어도 사용합니다. 2. HashSet에 대한 스레드 안전하지 않은 솔루션여기서 새로운 HashSet인 경우 위의 ArrayList와 동일한 동시 수정 예외가 계속 발생할 수 있습니다. 해결 방법은 코드의 주석을 참조하세요.package test.notsafe; import java.util.Collections; import java.util.HashSet; import java.util.Set; import java.util.UUID; import java.util.concurrent.CopyOnWriteArraySet; /** * 演示HashSet的线程不安全问题及解决方案 */ public class ThreadDemo3 { public static void main(String[] args) { //Set<String> set = new HashSet<>(); //解决方法1:Collections //Set<String> set = Collections.synchronizedSet(new HashSet<>()); //解决方法2:CopyOnWriteArraySet Set<String> set = new CopyOnWriteArraySet<>(); for (int i = 0; i < 20; i++) { new Thread(() -> { set.add(UUID.randomUUID().toString().substring(0,8)); System.out.println(set); },String.valueOf(i)).start(); } } }3. HashMap을 위한 스레드 안전하지 않은 솔루션
package test.notsafe; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; /** * 演示HashMap的线程不安全问题及解决方案 */ public class ThreadDemo4 { public static void main(String[] args) { //Map<String,Object> map = new HashMap<>(); //解决方法1:Collections //Map<String,Object> map = Collections.synchronizedMap(new HashMap<>()); //解决方法2:ConcurrentHashMap Map<String,Object> map = new ConcurrentHashMap<>(); for (int i = 0; i < 10; i++) { String key = String.valueOf(i); new Thread(() -> { map.put(key,UUID.randomUUID().toString().substring(0,8)); System.out.println(map); },String.valueOf(i)).start(); } } }
위 내용은 Java의 동시성 멀티 스레드 환경에서 ArrayList, HashSet 및 HashMap의 스레드 안전성을 보장하는 방법은 무엇입니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!