>  기사  >  Java  >  Java의 동시성 멀티 스레드 환경에서 ArrayList, HashSet 및 HashMap의 스레드 안전성을 보장하는 방법은 무엇입니까?

Java의 동시성 멀티 스레드 환경에서 ArrayList, HashSet 및 HashMap의 스레드 안전성을 보장하는 방법은 무엇입니까?

王林
王林앞으로
2023-05-09 22:49:071639검색

1. ArrayList에 대한 스레드 안전하지 않은 솔루션

메인 메서드에서 첫 번째 주석 줄을 몇 번 실행하면 다음과 같은 예외 메시지가 표시됩니다. 동시 수정 예외, 우선 ArrayList는 스레드에 안전하지 않습니다. 이 예외가 발생하는 이유는 첫 번째 스레드가 추가 작업을 수행하기 위해 방금 ArrayList 컬렉션에 들어갔을 때 다른 스레드도 추가 작업을 수행하기 위해 들어왔기 때문입니다. 세 번째 스레드가 들어와서 가져오기 작업을 수행하면 읽기와 쓰기를 동기화할 수 없게 되고 결국 결과를 인쇄할 때 폭발하게 됩니다.

해결책은 코드의 나머지 주석 줄을 살펴보는 것입니다. Java의 동시성 멀티 스레드 환경에서 ArrayList, HashSet 및 HashMap의 스레드 안전성을 보장하는 방법은 무엇입니까?

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 메소드를 호출하여 원래 컨테이너의 참조가 이 새 컨테이너를 가리키도록 합니다. 그러면 이 작업의 장점은 원래 컨테이너가 무엇이든 새 컨테이너에 요소를 추가하고 다른 스레드가 요소를 가져오고 읽으려는 경우 여전히 원래 컨테이너에서 읽습니다(즉, 여러 스레드가 동시에 읽을 수 있음). ; 그리고 다른 스레드가 추가하려면 다른 스레드가 완료될 때까지 기다린 다음 원래 컨테이너의 참조를 새 컨테이너로 지정해야 합니다. Java의 동시성 멀티 스레드 환경에서 ArrayList, HashSet 및 HashMap의 스레드 안전성을 보장하는 방법은 무엇입니까?

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 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 yisu.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제