Java中實現執行緒安全HashSet的幾種方法 | baeldung
在本教程中,我們將瞭解建立執行緒安全HashSet例項的可能性以及HashSet的ConcurrentHashMap的等價物。此外,我們將研究每種方法的優缺點。
使用ConcurrentHashMap工廠方法的執行緒安全HashSet
首先,我們將檢視公開靜態newKeySet()方法的ConcurrentHashMap類。基本上,此方法返回一個尊重java.util.Set介面的例項,並允許使用標準方法,如add()、contains()等。
這可以簡單地建立為:
Set<Integer> threadSafeUniqueNumbers = ConcurrentHashMap.newKeySet(); threadSafeUniqueNumbers.add(23); threadSafeUniqueNumbers.add(45); |
此外,返回的Set的效能類似於Has hSet,因為兩者都是使用基於雜湊的演算法實現的。此外,同步邏輯帶來的額外開銷也很小,因為實現使用了ConcurrentHashMap。
最後,缺點是該方法僅從 Java 8 開始存在。
使用ConcurrentHashMap例項方法的執行緒安全HashSet
至此,我們已經瞭解了ConcurrentHashMap 的靜態方法。接下來,我們將處理可用於ConcurrentHashMap的例項方法來建立執行緒安全的Set例項。有兩種方法可用,newKeySet()和newKeySet(defaultValue),它們彼此略有不同。
這兩種方法都建立了一個與原始map連結的Set。換句話說,每次我們向原始ConcurrentHashMap 新增一個新條目時, Set都會接收該值。此外,讓我們看看這兩種方法之間的區別。
- newKeySet ()方法
如上所述,newKeySet()公開了一個包含原始對映的所有鍵的Set 。此方法與newKeySet(defaultValue)的主要區別在於當前方法不支援向Set新增新元素。因此,如果我們嘗試呼叫add()或addAll() 之類的方法,我們將得到 UnsupportedOperationException。
儘管remove(object)或clear()之類的操作按預期工作,但我們需要注意Set上的任何更改都將反映在原始對映map中:
ConcurrentHashMap<Integer,String> numbersMap = new ConcurrentHashMap<>(); Set<Integer> numbersSet = numbersMap.keySet(); numbersMap.put(1, "One"); numbersMap.put(2, "Two"); numbersMap.put(3, "Three"); System.out.println("Map before remove: "+ numbersMap); System.out.println("Set before remove: "+ numbersSet); numbersSet.remove(2); System.out.println("Set after remove: "+ numbersSet); System.out.println("Map after remove: "+ numbersMap); |
輸出:
Map before remove: {1=One, 2=Two, 3=Three} Set before remove: [1, 2, 3] Set after remove: [1, 3] Map after remove: {1=One, 3=Three} |
- newKeySet (defaultValue)方法
讓我們看看另一種使用地圖中的鍵建立Set的方法。與上面提到的相比,newKeySet(defaultValue)返回一個Set例項,該例項支援通過呼叫set 上的add()或addAll()來新增新元素。
進一步檢視作為引數傳遞的預設值,這被用作地圖中新增的每個新條目的值add()或addAll()方法。以下示例顯示了它是如何工作的:
ConcurrentHashMap<Integer,String> numbersMap = new ConcurrentHashMap<>(); Set<Integer> numbersSet = numbersMap.keySet("SET-ENTRY"); numbersMap.put(1, "One"); numbersMap.put(2, "Two"); numbersMap.put(3, "Three"); System.out.println("Map before add: "+ numbersMap); System.out.println("Set before add: "+ numbersSet); numbersSet.addAll(asList(4,5)); System.out.println("Map after add: "+ numbersMap); System.out.println("Set after add: "+ numbersSet); |
下面是上面程式碼的輸出:
Map before add: {1=One, 2=Two, 3=Three} Set before add: [1, 2, 3] Map after add: {1=One, 2=Two, 3=Three, 4=SET-ENTRY, 5=SET-ENTRY} Set after add: [1, 2, 3, 4, 5] |
使用集合實用程式類的執行緒安全HashSet
讓我們使用java.util.Collections 中可用的synchronizedSet()方法來建立一個執行緒安全的HashSet例項:
Set<Integer> syncNumbers = Collections.synchronizedSet(new HashSet<>()); syncNumbers.add(1); |
在使用這種方法之前,我們需要意識到它的效率不如上面討論的那些。與實現低階併發機制的ConcurrentHashMap相比, synchronizedSet()基本上 只是將Set例項包裝到同步裝飾器中。
使用CopyOnWriteArraySet 的執行緒安全集
建立執行緒安全Set實現的最後一種方法是CopyOnWriteArraySet。建立這個Set的例項很簡單:
Set<Integer> copyOnArraySet = new CopyOnWriteArraySet<>(); copyOnArraySet.add(1); |
儘管使用這個類看起來很有吸引力,但我們需要考慮一些嚴重的效能缺陷。在幕後,CopyOnWriteArraySet使用Array 而不是HashMap來儲存資料。這意味著像contains()或remove()這樣的操作有 O(n) 的複雜度,而當使用由ConcurrentHashMap 支援的 Set 時,複雜度是 O(1)。
建議在Set大小通常保持較小且只讀操作佔多數時使用此實現。
結論
在本文中,我們看到了建立執行緒安全Set例項的不同可能性,並強調了它們之間的區別。首先我們看到了ConcurrentHashMap.newKeySet() 靜態方法。當需要執行緒安全的HashSet時,這應該是首選。之後我們檢視了ConcurrentHashMap靜態方法和 用於ConcurrentHashMap 例項的newKeySet()、newKeySet(defaultValue)之間的區別。
最後我們還討論了集合。synchronizedSet()和CopyOnWriteArraySet 存在效能缺陷。
像往常一樣,完整的原始碼可以在 GitHub 上找到。
相關文章
- Java面試之Java中實現多執行緒有幾種方法Java面試執行緒
- Java建立多執行緒的幾種方式實現Java執行緒
- Java多執行緒【三種實現方法】Java執行緒
- java 多執行緒之使用 interrupt 停止執行緒的幾種方法Java執行緒
- Java提供的幾種執行緒池Java執行緒
- 詳細分析 Java 中實現多執行緒的方法有幾種?(從本質上出發)Java執行緒
- Map實現執行緒安全的3種方式執行緒
- java各種集合的執行緒安全Java執行緒
- Java中實現執行緒的方式Java執行緒
- Java實現多執行緒的三種方式Java執行緒
- 在 C++ 中,實現執行緒同步主要有以下幾種常見方法C++執行緒
- Java多種方法實現等待所有子執行緒完成再繼續執行Java執行緒
- 主執行緒等待所有其他執行緒執行完畢,然後再繼續執行主執行緒的邏輯,有以下幾種方法可以實現:執行緒
- Java中如何實現執行緒呢?Java執行緒
- 終止java執行緒的2種方法Java執行緒
- Java建立多執行緒的一種方法Java執行緒
- 【多執行緒高併發程式設計】二 實現多執行緒的幾種方式執行緒程式設計
- java--執行緒池--建立執行緒池的幾種方式與執行緒池操作詳解Java執行緒
- Java中確保執行緒安全最常用的兩種方式Java執行緒
- String中hashCode方法的執行緒安全執行緒
- 【Java多執行緒】執行緒安全的集合Java執行緒
- Java多執行緒的實現Java執行緒
- Java執行緒池newCachedThreadPool()與newFixedThreadPool()區別 | BaeldungJava執行緒thread
- Java 執行緒池中的執行緒複用是如何實現的?Java執行緒
- Java併發實戰一:執行緒與執行緒安全Java執行緒
- Java多執行緒中執行緒安全與鎖問題Java執行緒
- 獲取Java執行緒返回值的幾種方式Java執行緒
- Java執行緒安全Java執行緒
- java執行緒實現方式Java執行緒
- 模板方法中的執行緒安全問題執行緒
- java執行緒實現的三種方式以及靜態代理Java執行緒
- 執行緒池建立的幾種方式執行緒
- SpringBoot執行緒池和Java執行緒池的實現原理Spring Boot執行緒Java
- 執行緒池的五種狀態及建立執行緒池的幾種方式執行緒
- 多執行緒面試題之多執行緒有幾種實現方案,分別是什麼執行緒面試題
- Java執行緒(一):執行緒安全與不安全Java執行緒
- Java幾種執行緒池及任務佇列Java執行緒佇列
- iOS多執行緒安全-13種執行緒鎖?iOS執行緒