Java併發之ConcurrentHashMap
ConcurrentHashMap,執行緒安全的HashMap,由於HashTable較重量級,他會給整個加鎖,而ConcurrentHashMap只是給每個Segment加鎖,所以效能快很多。
除了initialCapacity、loadFactor之外,還有一個concurrentLevel屬性,預設情況下,三個屬性分別為16,0.75,16
設定以上三個屬性後,就得考慮鎖加在哪?並怎樣初始化加鎖的物件?
點選(此處)摺疊或開啟
-
int sshift = 0;
-
int ssize = 1;
-
while(ssize < concurrentLevel){
-
++sshift;
-
ssize <<= 1;
- }
上面這段程式碼意思是:計算出一個不小於concurrentLevel的ssize值,而且它是2的n次方。
預設情況下,ssize為16,根據這個引數傳入Segment的newArray方法,建立大小為16的Segment陣列
建立Segment陣列後,陣列元素物件怎麼初始化?
點選(此處)摺疊或開啟
-
int c = initialCapacity /ssize
-
if(c* ssize < initialCapacity){
-
++c;
-
}
-
int cap = 1;
-
while(cap < c){
-
cap << 1;
- }
上面程式碼意思是:用Map容量除以Segment陣列大小,看每個Segment需要初始化多大,這裡16/16=1,所以建立大小為cap=1的HashEntry[]陣列,將其賦給Segment,並且基於cap值和loadFactor計算threshold值。Segment繼承自ReentrantLock。可以發現。一個Segment的資料結構就相當於HashMap(陣列下有連結串列)
點選(此處)摺疊或開啟
- threshold = (int)(newTable.length * loadFactor)
put(key,value)
ConcurrentHashMap並沒有對整個方法加鎖(而HashTable對整個加鎖),和HashMap一樣,首先對key.hashCode進行hash操作,得到hash值後計算其對應在陣列中的哪個Segment物件。
點選(此處)摺疊或開啟
- return segments[(hash >>> segmentShift) & segmentMask]
找到陣列中的Segment物件後,接著呼叫Segment的put方法完成操作,至此,才對其進行加鎖:lock,接著判斷當前儲存的物件個數加1後是否大於threshold,如大於,則rehash,將當前HashEntry[]陣列擴大2倍,並重hash物件。
其餘的操作跟HashMap差不多,有則覆蓋,沒有則新建立HashEntry物件,放在連結串列頭部。
點選(此處)摺疊或開啟
- HashEntry<K,V>[] newTable = HashEntry.newArray(oldCapacity<<1)
get(key)
get操作只有在e.value == null的情況下,才會加lock再執行一次e.value
問題:get操作大部分情況沒有lock,它是怎樣保證併發下資料的一致性的呢?
譬如1:在get找HashEntry連結串列過程中,這時候可能HashEntry[]陣列會發生改變(put操作執行),那它是如何讓保證的呢?
答案就是因為HashEntry[]陣列是volatile的,當put改變陣列後,get操作會立刻得到更新。並且,jdk5以後,volatile語義增強了,不僅僅保證資料的可見性,還能保證禁止在物件上的讀寫重排序,所以,在get時讀取到的HashEntry[]是最新的、並且構造已經完全的
譬如2:當get操作已經找到了HashEntry,準備開始遍歷連結串列了,這時HashEntry發生變化了怎麼辦?
答案就是HashEntry物件中的hash、key、next屬性都是final的,這就意味著不能插入一個新的HashEntry在所遍歷的任何HashEntry的next下,這樣就可以保證當獲取到HashEntry物件後,其基於next屬性構建的連結串列是不會發生變化的。
還有一個問題,為什麼要判斷e.value是否為null?而且如果為null再呼叫readValueUnderLock(HashEntry e)?
以下為readValueUnderLock方法:
點選(此處)摺疊或開啟
-
/**
-
* Reads value field of an entry under lock. Called if value
-
* field ever appears to be null. This is possible only if a
-
* compiler happens to reorder a HashEntry initialization with
-
* its table assignment, which is legal under memory model
-
* but is not known to ever occur.
-
*/
-
V readValueUnderLock(HashEntry<K,V> e) {
-
lock();
-
try {
-
return e.value;
-
} finally {
-
unlock();
-
}
- }
透過它的註釋,我們明白了,This is possible only if a compiler happens to reorder a HashEntry initialization with its table assignment,意思就是,只有在HashEntry初始化時出現指令重排,才會導致該方法呼叫,並且也不確定是否發生。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/28912557/viewspace-1133899/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Java併發5:ConcurrentHashMapJavaHashMap
- Java併發——ConcurrentHashMap(JDK 1.8)JavaHashMapJDK
- [Java併發]Concurrenthashmap的size()JavaHashMap
- 併發容器之ConcurrentHashMap(JDK 1.8版本)HashMapJDK
- Java併發指南13:Java 中的 HashMap 和 ConcurrentHashMap 全解析JavaHashMap
- Java ConcurrentHashMap 高併發安全實現原理解析JavaHashMap
- Java併發集合類ConcurrentHashMap底層核心原始碼解析JavaHashMap原始碼
- java併發之synchronizedJavasynchronized
- Java併發之ExecutorJava
- java併發之CopyOnWriteArrayListJava
- 併發程式設計之 ConcurrentHashMap(JDK 1.8) putVal 原始碼分析程式設計HashMapJDK原始碼
- Java併發指南13:Java7/8 中的 HashMap 和 ConcurrentHashMap 全解析JavaHashMap
- 併發-7-同步容器和ConcurrentHashMapHashMap
- java併發程式設計工具類JUC第八篇:ConcurrentHashMapJava程式設計HashMap
- Java併發包之 CopyOnWriteArrayListJava
- 併發程式設計之ConcurrentHashMap jdk1.7和1.8原始碼剖析程式設計HashMapJDK原始碼
- java併發之ConcurrentLinkedQueueJava
- java併發之hashmap原始碼JavaHashMap原始碼
- Java併發之AQS原理剖析JavaAQS
- Java併發之AQS詳解JavaAQS
- Java併發系列之volatileJava
- Java 併發包之CountDownLatch、CyclicBarrierJavaCountDownLatch
- Java併發之顯式鎖Java
- Java之併發三問題Java
- 併發程式設計 —— ConcurrentHashMap size 方法原理分析程式設計HashMap
- 帶你走進Java集合之ConcurrentHashMapJavaHashMap
- Java集合之ConcurrentHashMap原始碼淺析JavaHashMap原始碼
- Java併發程式設計之Java CAS操作Java程式設計
- Java併發之等待/通知機制Java
- java併發面試常識之copyonwriteJava面試
- Java併發之CompletionService詳解Java
- java併發之SynchronousQueue實現原理Java
- Java併發程式設計之synchronizedJava程式設計synchronized
- Java高併發之CyclicBarrier簡介Java
- Java併發之Executor + Callable + FutureJava
- Java併發之CountDownLatch、CyclicBarrier和SemaphoreJavaCountDownLatch
- Java 併發模式之Master-WorkerJava模式AST
- Java併發包原始碼學習系列:JDK1.8的ConcurrentHashMap原始碼解析Java原始碼JDKHashMap