スレッド セーフとは何ですか? データの読み取りと書き込みがスレッドから分離されている必要があり、データの損失や不整合が発生しないことを意味します。データが変更されるたびに上書きされるべきではありません。
銀行引き出しの典型的な例を考えてみましょう。アカウント A は最初は 0、スレッド A は 0 を読み取り、その後 100 を保存します (データはまだ書き込まれません)。スレッド B は 0 を読み取り、100 も保存します。 time 最後に表示されるアカウントの残高は 100 です。これは非科学的であり、スレッドアンセーフと呼ばれます。したがって、入出金のオブジェクトを制御し、操作するオブジェクトにデータロックをかけて、データを更新した後、他のスレッドがスレッドセーフを実現できるようにする必要があります。
今回は HashSet を証明します。Set インターフェースが実装されていることはわかっています。 Set の特徴は、保存されたデータが繰り返されないことです。なぜなら、まず内部に保存されているデータを読み込んで存在するかどうかを確認し、存在する場合は保存されず、存在しない場合は保存されます。つまり、データの保存操作は、最初に読み取り、次に書き込みという 2 つのステップに分割されます。スレッドセーフではないと仮定すると、スレッド A が設定されたオブジェクトに要素がないと判断し、要素を挿入しようとしているときに、スレッド B もオブジェクトに要素がないと判断し、挿入されないという状況が考えられます。最終的には、2 つの同一の要素が挿入されます。
デモは次のように設計します:
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 が表示されることがあります。 5000 を超える状況。これにより、前述の状況が発生し、HashSet がスレッドセーフなクラスではないことが証明されます。
実際、ソース コードを見ると、HashMap は HashSet の内部でデータを維持するために使用されていることがわかりました。その根本的な理由は、HashMap がスレッドセーフなクラスではないことです。これは、HashSet の非スレッド安全性につながります。 Java コレクション クラスの詳細については、[PHP 中国語 Web サイト: java ビデオ ]
最後に、完全なコード ケースの検証:
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 中国語 Web サイトの他の関連記事を参照してください。