不好意思,我併發幾乎沒學,這章沒法看,記一下基礎知識吧
回答
Java 提供了不同層面的線程安全支持。在傳統集合框架內部,除了Hashtable
等同步容器,還提供了所謂的同步包裝器(Synchronized Wrapper
),我們可以調用Collections
工具類提供的包裝方法,來獲取一個同步的包裝容器(如Collections.synchronizedMap
),但是它們都是利用非常粗粒度的同步方式,在高併發情況下,性能比較低下。
另外,更加普遍的選擇是利用併發包提供的線程安全容器類,它提供了:
- 各種併發容器,比如
ConcurrentHashMap
、CopyOnWriteArrayList
。 - 各種線程安全隊列(
Queue/Deque
),如ArrayBlockingQueue
、SynchronousQueue
。 - 各種有序容器的線程安全版本等。
具體保證線程安全的方式,包括有從簡單的synchronize
方式,到基於更加精細化的,比如基於分離鎖實現的ConcurrentHashMap
等併發實現等。具體選擇要看開發的場景需求,總體來說,併發包內提供的容器通用場景,遠優於早期的簡單同步實現。
ConcurrentHashMap和Hashtable的區別
ConcurrentHashMap和Hashtable的區別主要體現在實現線程安全的方式上不同。
- 底層數據結構: JDK1.8採用的數據結構跟HashMap1.8的結構- -樣,數組+鏈表/紅黑二叉樹。Hashtable和JDK1.8之前的HashMap的底層數據結構類似都是採用數組+鏈表的形式,數組是HashMap的主體,鏈表則是主要爲了解決哈希衝突而存在的;
- 實現線程安全的方式(重要) :
JDK1.8
用Node
數組+鏈表+紅黑樹的數據結構來實現,併發控制使用synchronized
和CAS
來操作。(JDK1.6
以後對synchronized
鎖做了很多優化)整個看起來就像是優化過且線程安全的HashMap,Hashtable
(同一把鎖) :使用synchronized
來保證線程安全,效率非常低下。當一個線程訪問同步方法時,其他線程也訪問同步方法,可能會進入阻塞或輪詢狀態,如使用put
添加元素,另一個線程不能使用put
添加元素,也不能使用get,
競爭會越來越激烈效率越低。