第五章:(2)HashSet 集合線程不安全&解決方案


一、HasheSet 集合的不安全

  1、故障現象

public class NotSafeSetDemo { public static void main(String[] args) { Set<String> set = new HashSet<>(); for (int i = 0; i < 30; i++) { new Thread(() -> { //向集合添加內容
                set.add(UUID.randomUUID().toString().substring(0, 8)); //從集合獲取內容
 System.out.println(set); }, String.valueOf(i)).start(); } } }

  運行結果:

  

 

  2、分析

  (1)HashSet 是線程不安全的
  (2)HashSet 的底層是一個 HashMap(), 但是這個 HashMap 的 value 永遠是一個 Object 類型的常量(PRESENT), 但HashSet的add是放一個值(調用map的PUT方法),而HashMap是放K、V鍵值對
public HashSet() { map = new HashMap<>(); } private static final Object PRESENT = new Object(); public boolean add(E e) { return map.put(e, PRESENT)==null; }

    因為底層使用的是 HashMap,而 HashMap 也是線程不安全的,並且 HashSet 的 add 方法也沒有使用 synchronized 同步鎖。

 

二、方案一

  1、使用 Collections 工具類

  Collections 工具類也提供了線程安全的 Set 集合。

  2、代碼實現

public class SafeSetDemo { public static void main(String[] args) { Set<String> set = Collections.synchronizedSet(new HashSet<>()); for (int i = 0; i < 30; i++) { new Thread(() -> { //向集合添加內容
                set.add(UUID.randomUUID().toString().substring(0, 8)); //從集合獲取內容
 System.out.println(set); }, String.valueOf(i)).start(); } } }

 

三、方案二

  1、使用 CopyOnWriteArraySet 

    原理同 CopyOnWriteArrayList。

  2、代碼實現

public class SafeSetDemo { public static void main(String[] args) {
 Set<String> set = new CopyOnWriteArraySet<>(); for (int i = 0; i < 30; i++) { new Thread(() -> { //向集合添加內容
                set.add(UUID.randomUUID().toString().substring(0, 8)); //從集合獲取內容
 System.out.println(set); }, String.valueOf(i)).start(); } } }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM