스레드 안전성이란 무엇입니까? 데이터 읽기 및 쓰기가 스레드 격리되어야 하며 데이터가 수정될 때마다 덮어쓰면 안 됩니다.
계좌 A는 처음에 0을 읽고 스레드 A는 0을 읽은 다음 100을 저장합니다(아직 데이터가 기록되지 않음). 스레드 B도 0을 읽고 100을 저장합니다. 이때 우리가 보는 최종 계좌의 잔액은 100이다. 이는 비과학적이며 스레드 안전하지 않다고 합니다. 따라서 우리는 입출금을 위한 개체를 제어해야 하며, 데이터를 업데이트한 후 다른 스레드가 스레드 안전을 달성할 수 있도록 우리가 운영하는 개체를 허용해야 합니다.
이번에는 HashSet을 증명하겠습니다. Set 인터페이스가 구현되어 있다는 것을 알고 있습니다. Set의 특징은 저장된 데이터가 반복되지 않는다는 것입니다. 먼저 내부에 저장된 데이터를 읽어서 존재 여부를 확인하기 때문에 존재하는 경우에는 저장되지 않고 그렇지 않은 경우에는 저장됩니다. 즉, 데이터 저장 작업은 먼저 읽기와 쓰기의 두 단계로 나누어집니다. 스레드로부터 안전하지 않다고 가정하면 스레드 A가 집합 개체에 요소가 없고 요소를 삽입하려고 한다고 판단할 때 스레드 B도 개체에 요소가 없다고 판단하여 요소를 삽입할 가능성이 매우 높습니다. 마지막으로 두 개의 동일한 요소가 삽입됩니다.
데모를 다음과 같이 디자인합니다:
class TestHashSet implements Runnable{ // 实现Runnable 让该集合能被多个线程访问 Set<Integer> set = new HashSet<Integer>(); // 线程的执行就是插入5000个整数 @Override public void run() { for (int i = 0;i < 5000;i ++) { set.add(i); } } }
메인 스레드에서 테스트합니다:
TestHashSet run2 = new TestHashSet(); // 实例化两个线程 Thread t6 = new Thread(run2); Thread t7 = new Thread(run2); // 启动两个线程 t6.start(); t7.start(); // 当前线程等待加入到调用线程后 t6.join(); t7.join(); // 打印出集合的size System.out.println(run2.set.size());
대부분의 인쇄 결과는 예상되는 5000입니다. , 그러나 때때로 5000보다 큰 상황이 있을 수 있습니다. 이는 앞서 언급한 상황으로 이어지며, 이는 HashSet이 스레드로부터 안전한 클래스가 아님을 증명합니다.
사실 소스 코드를 보면 HashSet이 HashMap을 사용하여 내부적으로 데이터를 유지 관리하는 것으로 나타났습니다. 근본적인 이유는 HashMap이 스레드로부터 안전한 클래스가 아니라는 것입니다. 이는 HashSet의 스레드가 아닌 안전성으로 이어집니다. Java 컬렉션 클래스에 대한 자세한 내용은 [PHP 중국어 웹사이트: javavideo]
마지막으로 전체 코드 케이스 확인을 살펴보겠습니다.
# 🎜🎜#
import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; /** * 验证HashSet不是线程安全 */ public class HashSetTest { public static void main(String[] args) { final Set<Integer> set = new HashSet<>();// 结果可能大于1000 // final Set<Integer> set = Collections.synchronizedSet(new HashSet<>());// 结果等于1000 // final Set<Integer> set = Collections.newSetFromMap(new ConcurrentHashMap<Integer, Boolean>());// 结果等于1000 // 往set写入1-1000 Runnable runnable = new Runnable() { @Override public void run() { for (int i = 1; i <= 1000; i++) { set.add(i); } } }; int threadNum = 10;// 线程数 List<Thread> threadList = new ArrayList<>(); for (int i = 0; i < threadNum; i++) { Thread thread = new Thread(runnable); threadList.add(thread); thread.start(); } // 主线程等待子线程执行完成 for (Thread thread : threadList) { try { thread.join(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(set.size());// 结果可能大于1000 } }
위 내용은 해시셋 스레드는 안전한가요?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!