1. 程式人生 > >Java執行緒安全的集合詳解

Java執行緒安全的集合詳解

一、早期執行緒安全的集合

我們先從早期的執行緒安全的集合說起,它們是Vector和HashTable

1.Vector

Vector和ArrayList類似,是長度可變的陣列,與ArrayList不同的是,Vector是執行緒安全的,它給幾乎所有的public方法都加上了synchronized關鍵字。由於加鎖導致效能降低,在不需要併發訪問同一物件時,這種強制性的同步機制就顯得多餘,所以現在Vector已被棄用

2.HashTable

HashTable和HashMap類似,不同點是HashTable是執行緒安全的,它給幾乎所有public方法都加上了synchronized關鍵字,還有一個不同點是HashTable的K,V都不能是null,但HashMap可以,它現在也因為效能原因被棄用了

二、Collections包裝方法

Vector和HashTable被棄用後,它們被ArrayList和HashMap代替,但它們不是執行緒安全的,所以Collections工具類中提供了相應的包裝方法把它們包裝成執行緒安全的集合

List<E> synArrayList = Collections.synchronizedList(new ArrayList<E>());

Set<E> synHashSet = Collections.synchronizedSet(new HashSet<E>());

Map<K,V> synHashMap = Collections.synchronizedMap(new HashMap<K,V>());

...

Collections針對每種集合都聲明瞭一個執行緒安全的包裝類,在原集合的基礎上添加了鎖物件,集合中的每個方法都通過這個鎖物件實現同步

三、java.util.concurrent包中的集合

1.ConcurrentHashMap

ConcurrentHashMap和HashTable都是執行緒安全的集合,它們的不同主要是加鎖粒度上的不同。HashTable的加鎖方法是給每個方法加上synchronized關鍵字,這樣鎖住的是整個Table物件。而ConcurrentHashMap是更細粒度的加鎖
在JDK1.8之前,ConcurrentHashMap加的是分段鎖,也就是Segment鎖,每個Segment含有整個table的一部分,這樣不同分段之間的併發操作就互不影響
JDK1.8對此做了進一步的改進,它取消了Segment欄位,直接在table元素上加鎖,實現對每一行進行加鎖,進一步減小了併發衝突的概率

2.CopyOnWriteArrayList和CopyOnWriteArraySet

它們是加了寫鎖的ArrayList和ArraySet,鎖住的是整個物件,但讀操作可以併發執行

3.

除此之外還有ConcurrentSkipListMap、ConcurrentSkipListSet、ConcurrentLinkedQueue、ConcurrentLinkedDeque等,至於為什麼沒有ConcurrentArrayList,原因是無法設計一個通用的而且可以規避ArrayList的併發瓶頸的執行緒安全的集合類,只能鎖住整個list,這用Collections裡的包裝類就能辦到