摘要:是線程安全,性能出色的的線程安全實現(xiàn),相比較他是線程安全的,相比較他的性能優(yōu)勢非常明顯。的源碼其實很簡單,和的結(jié)構(gòu)一致,但是每一個方法都是用來修飾,以保證操作是線程安全的。這樣在多線程的情況下,只有一個線程獲取鎖操作中的數(shù)據(jù)。
ConcurrentHashMap
ConcurrentHashMap是線程安全,性能出色的Map的線程安全實現(xiàn),相比較HashMap他是線程安全的,相比較HashTable他的性能優(yōu)勢非常明顯。他的使用很簡單,這里主要是想要探究一下ConcurrentHashMap的實現(xiàn)原理。
在這里一共有 個問題需要搞明白。
ConcurrentHashMap為什么比HashTable的性能要高?
ConcurrentHashMap在JDK8和JDK7有什么變化,為什么會有這種變化,對我們開發(fā)有什么啟示?
為什么在JDK8中使用Synchronized而不是用ReentrantLock來實現(xiàn)加鎖?
帶著這幾個問題我們來分析一下ConcurrentHashMap的源碼吧。
在JDK8(JDK7也是一樣)中ConcurrentHashMap的定義如下:
public class ConcurrentHashMapextends AbstractMap implements ConcurrentMap , Serializable {
Java7中ConcurrentHashMap的實現(xiàn)是基于分段鎖實現(xiàn)的。他的底層數(shù)據(jù)結(jié)構(gòu)仍然是數(shù)組+鏈表,與HashTable不同的是,ConcurrentHashMap的最外層不是一個大的數(shù)組,而是一個Segment數(shù)組(分段鎖的實現(xiàn))。分段鎖減小了鎖的粒度,提高了并發(fā)程度。這也是為什么比HashTable效率要高的原因。
HashTable的源碼其實很簡單,HashTable和HashMap的結(jié)構(gòu)一致,但是每一個方法都是用Synchronized來修飾,以保證操作是線程安全的。這樣在多線程的情況下,只有一個線程獲取鎖操作hashTable中的數(shù)據(jù)。而CourrentHashMap則不是,它允許最多有segment數(shù)組長度個線程同時操作ConcurrentHashMap中的數(shù)據(jù)。
ConcurrentHashMap的整體結(jié)構(gòu)如下(圖片來源:http://www.jasongj.com/java/c...):
ConcurrentHashMap的定義:
public class ConcurrentHashMapextends AbstractMap implements ConcurrentMap , Serializable { private static final long serialVersionUID = 7249069246763182397L; /** * 表的默認(rèn)容量 */ static final int DEFAULT_INITIAL_CAPACITY = 16; /** * 默認(rèn)擴容因子 */ static final float DEFAULT_LOAD_FACTOR = 0.75f; /** * segments數(shù)組的默認(rèn)長度,為了能通過按位與的散列算法來定位segments數(shù)組的索引,必須保證segments數(shù)組的長度是2的N次方 */ static final int DEFAULT_CONCURRENCY_LEVEL = 16; /** * HashEntry最大容量 */ static final int MAXIMUM_CAPACITY = 1 << 30; /** * segment的最小容量 */ static final int MIN_SEGMENT_TABLE_CAPACITY = 2; /** * segment的最大容量 */ static final int MAX_SEGMENTS = 1 << 16; // slightly conservative /** * 重試次數(shù),無鎖的情況下嘗試兩次 */ static final int RETRIES_BEFORE_LOCK = 2; /** * 散列運算的掩碼,等于ssize-1 */ final int segmentMask; /** * 定位參與散列運算的位數(shù),等于32-sshift */ final int segmentShift; /** * 定義segment數(shù)組 */ final Segment [] segments;
Segment定義:
static final class Segmentextends ReentrantLock implements Serializable { transient volatile HashEntry [] table; transient int count; transient int modCount; //擴容量,默認(rèn)為表的容量*加載因子,實際量超過這個值的時候,進行擴容 transient int threshold; //segment中hashEntry的擴容因子 final float loadFactor; }
get()操作經(jīng)過兩次散列找到HashEntry,然后進行遍歷的操作,get方法使用的變量都是volatile類型的,可以保證線程可見,能夠被多線程同時讀,并且保證不會讀取到過期的值,在get操作中需要讀count和value兩個共享變量,所以不需要加鎖,volatile字段的寫入操作會先于讀操作,所有即使有一個線程在修改,get也能獲取到最新的值。
put() 先對變量的hashCode進行一次再散列然后定位到Segment,然后再Segment中進行插入操作。如果HashEntry數(shù)組超過threshold,那么擴容,擴容只是針對Segment進行擴容。
size() 統(tǒng)計ConcurrentHashMap中元素的個數(shù),需要對Segment中所有元素進行求和,Segment里全局變量count是一個volatile類型的變量,累加可以獲取元素的總個數(shù),但是不一定準(zhǔn)確,因為使用過的count再后面可以改變,最后的方法就是阻塞put,remove,clean等元素操作的方法,但是這樣非常低效。所以Concurrenthashmap通過嘗試兩次不鎖來統(tǒng)計segment的元素大小,如果兩次結(jié)果不一樣,那么使用加鎖的方式來統(tǒng)計,容器是否變化是通過modCount是否變化來確定的。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/77795.html
摘要:中的使用及在中的沖突方案引言簡稱是在作為的替代選擇新引入的,是包的重要成員。為了解決在頻繁沖突時性能降低的問題,中使用平衡樹來替代鏈表存儲沖突的元素。目前,只有和會在頻繁沖突的情況下使用平衡樹。 java中ConcurrentHashMap的使用及在Java 8中的沖突方案 1、引言 ConcurrentHashMap(簡稱CHM)是在Java 1.5作為Hashtable的替代選擇新...
摘要:在中一般來說通過來創(chuàng)建所需要的線程池,如高并發(fā)原理初探后端掘金閱前熱身為了更加形象的說明同步異步阻塞非阻塞,我們以小明去買奶茶為例。 AbstractQueuedSynchronizer 超詳細(xì)原理解析 - 后端 - 掘金今天我們來研究學(xué)習(xí)一下AbstractQueuedSynchronizer類的相關(guān)原理,java.util.concurrent包中很多類都依賴于這個類所提供的隊列式...
摘要:在中一般來說通過來創(chuàng)建所需要的線程池,如高并發(fā)原理初探后端掘金閱前熱身為了更加形象的說明同步異步阻塞非阻塞,我們以小明去買奶茶為例。 AbstractQueuedSynchronizer 超詳細(xì)原理解析 - 后端 - 掘金今天我們來研究學(xué)習(xí)一下AbstractQueuedSynchronizer類的相關(guān)原理,java.util.concurrent包中很多類都依賴于這個類所提供的隊列式...
摘要:表示的是兩個,當(dāng)其中任意一個計算完并發(fā)編程之是線程安全并且高效的,在并發(fā)編程中經(jīng)常可見它的使用,在開始分析它的高并發(fā)實現(xiàn)機制前,先講講廢話,看看它是如何被引入的。電商秒殺和搶購,是兩個比較典型的互聯(lián)網(wǎng)高并發(fā)場景。 干貨:深度剖析分布式搜索引擎設(shè)計 分布式,高可用,和機器學(xué)習(xí)一樣,最近幾年被提及得最多的名詞,聽名字多牛逼,來,我們一步一步來擊破前兩個名詞,今天我們首先來說說分布式。 探究...
閱讀 2796·2021-11-16 11:44
閱讀 969·2021-10-09 09:58
閱讀 4489·2021-09-24 09:48
閱讀 4249·2021-09-23 11:56
閱讀 2407·2021-09-22 15:48
閱讀 1892·2021-09-07 10:07
閱讀 3204·2021-08-31 09:46
閱讀 504·2019-08-30 15:56