Java 中ConcurrentHashMap的實現(xiàn)
ConcurrentHashMap(簡稱CHM)是在Java 1.5作為Hashtable的替代選擇新引入的,是concurrent包的重要成員。在Java 1.5之前,如果想要實現(xiàn)一個可以在多線程和并發(fā)的程序中安全使用的Map,只能在HashTable和synchronized Map中選擇,因為HashMap并不是線程安全的。但再引入了CHM之后,我們有了更好的選擇。CHM不但是線程安全的,而且比HashTable和synchronizedMap的性能要好。相對于HashTable和synchronizedMap鎖住了整個Map,CHM只鎖住部分Map。CHM允許并發(fā)的讀操作,同時通過同步鎖在寫操作時保持數(shù)據(jù)完整性。我們已經(jīng)在Top 5 Java Concurrent Collections from JDK 5 and 6中學習了CHM的基礎知識,在這篇博客中我將介紹以下幾點:
- CHM在Java中如何實現(xiàn)的
- 什么情況下應該使用CHM
- 在Java中使用CHM的例子
- CHM的一些重要特性
Java中ConcurrentHashMap的實現(xiàn)
CHM引入了分割,并提供了HashTable支持的所有的功能。在CHM中,支持多線程對Map做讀操作,并且不需要任何的blocking。這得益于CHM將Map分割成了不同的部分,在執(zhí)行更新操作時只鎖住一部分。根據(jù)默認的并發(fā)級別(concurrency level),Map被分割成16個部分,并且由不同的鎖控制。這意味著,同時最多可以有16個寫線程操作Map。試想一下,由只能一個線程進入變成同時可由16個寫線程同時進入(讀線程幾乎不受限制),性能的提升是顯而易見的。但由于一些更新操作,如put(),remove(),putAll(),clear()只鎖住操作的部分,所以在檢索操作不能保證返回的是最新的結果。
另一個重要點是在迭代遍歷CHM時,keySet返回的iterator是弱一致和fail-safe的,可能不會返回某些最近的改變,并且在遍歷過程中,如果已經(jīng)遍歷的數(shù)組上的內容變化了,不會拋出ConcurrentModificationExceptoin的異常。
CHM默認的并發(fā)級別是16,但可以在創(chuàng)建CHM時通過構造函數(shù)改變。毫無疑問,并發(fā)級別代表著并發(fā)執(zhí)行更新操作的數(shù)目,所以如果只有很少的線程會更新Map,那么建議設置一個低的并發(fā)級別。另外,CHM還使用了ReentrantLock來對segments加鎖。
Java中ConcurrentHashMap putifAbsent方法的例子
很多時候我們希望在元素不存在時插入元素,我們一般會像下面那樣寫代碼
synchronized(map){ if (map.get(key) == null){ return map.put(key, value); } else{ return map.get(key); } }
上面這段代碼在HashMap和HashTable中是好用的,但在CHM中是有出錯的風險的。這是因為CHM在put操作時并沒有對整個Map加鎖,所以一個線程正在put(k,v)的時候,另一個線程調用get(k)會得到null,這就會造成一個線程put的值會被另一個線程put的值所覆蓋。當然,你可以將代碼封裝到synchronized代碼塊中,這樣雖然線程安全了,但會使你的代碼變成了單線程。CHM提供的putIfAbsent(key,value)方法原子性的實現(xiàn)了同樣的功能,同時避免了上面的線程競爭的風險。
什么時候使用ConcurrentHashMap
CHM適用于讀者數(shù)量超過寫者時,當寫者數(shù)量大于等于讀者時,CHM的性能是低于Hashtable和synchronized Map的。這是因為當鎖住了整個Map時,讀操作要等待對同一部分執(zhí)行寫操作的線程結束。CHM適用于做cache,在程序啟動時初始化,之后可以被多個請求線程訪問。正如Javadoc說明的那樣,CHM是HashTable一個很好的替代,但要記住,CHM的比HashTable的同步性稍弱。
總結
現(xiàn)在我們知道了什么是ConcurrentHashMap和什么時候該用ConcurrentHashMap,下面我們來復習一下CHM的一些關鍵點。
- CHM允許并發(fā)的讀和線程安全的更新操作
- 在執(zhí)行寫操作時,CHM只鎖住部分的Map
- 并發(fā)的更新是通過內部根據(jù)并發(fā)級別將Map分割成小部分實現(xiàn)的
- 高的并發(fā)級別會造成時間和空間的浪費,低的并發(fā)級別在寫線程多時會引起線程間的競爭
- CHM的所有操作都是線程安全
- CHM返回的迭代器是弱一致性,fail-safe并且不會拋出ConcurrentModificationException異常
- CHM不允許null的鍵值
- 可以使用CHM代替HashTable,但要記住CHM不會鎖住整個Map
以上就是Java中CHM的實現(xiàn)和使用場景,希望能幫助到大家!謝謝大家對本站的支持!
- Java ConcurrentHashMap的使用示例
- Java7和Java8中的ConcurrentHashMap原理解析
- JAVA核心知識之ConcurrentHashMap源碼分析
- Java中遍歷ConcurrentHashMap的四種方式詳解
- java ConcurrentHashMap鎖分段技術及原理詳解
- 深入學習java并發(fā)包ConcurrentHashMap源碼
- Java源碼解析ConcurrentHashMap的初始化
- java中ConcurrentHashMap的讀操作為什么不需要加鎖
- Java并發(fā)系列之ConcurrentHashMap源碼分析
- java基于ConcurrentHashMap設計細粒度實現(xiàn)代碼
- Java concurrency集合之ConcurrentHashMap_動力節(jié)點Java學院整理
- 基于Java并發(fā)容器ConcurrentHashMap#put方法解析
- java 使用ConcurrentHashMap和計數(shù)器實現(xiàn)鎖
- 淺談Java源碼ConcurrentHashMap
相關文章
Java中SpringBoot的@Transactional原理
這篇文章主要介紹了Java中SpringBoot的@Transactional原理,面向元數(shù)據(jù)遍歷已經(jīng)成為越來越多開發(fā)者的偏好,因此原理從Springboot的EnableTransactionManagement注解說起,需要的朋友可以參考下2023-07-07java使用Validation進行數(shù)據(jù)校驗的方式總結
在Java中提供了一系列的校驗方式,下面這篇文章主要給大家介紹了關于java使用Validation進行數(shù)據(jù)校驗的相關資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下2023-06-06Netty中ChannelPoolHandler調用處理程序詳解
這篇文章主要介紹了Netty中ChannelPoolHandler調用處理程序詳解,Netty 是基于 Java NIO 的異步事件驅動的網(wǎng)絡應用框架,使用 Netty 可以快速開發(fā)網(wǎng)絡應用,Netty 提供了高層次的抽象來簡化 TCP 和 UDP 服務器的編程,但是你仍然可以使用底層的 API,需要的朋友可以參考下2023-11-11Java+MySQL實現(xiàn)學生信息管理系統(tǒng)源碼
這篇文章主要為大家詳細介紹了Java+MySQL實現(xiàn)學生信息管理系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-11-11