[英]Need simple explanation how “lock striping” works with ConcurrentHashMap
根據Java Concurrency in Practice,第11.4.3章說:
鎖分裂有時可以擴展到一組變量獨立對象的分區鎖定,在這種情況下,它被稱為鎖定條帶。 例如,ConcurrentHashMap的實現使用一個包含16個鎖的數組,每個鎖保護1/16的散列桶; 鏟斗N由鎖定N mod 16保護。
我仍然有理解和可視化鎖條紋和鏟斗機制的問題。 有人可以用很好理解的話來解釋這個:)
提前致謝。
哈希映射構建在數組上,其中哈希函數將對象映射到基礎數組中的元素。 假設底層數組有1024個元素 - ConcurrentHashMap實際上將其轉換為16個不同的64個元素的子數組,例如{0,63},{64,127}等。每個子數組都有自己的鎖,所以修改{0,63}子數組不影響{64,127}子數組 - 一個線程可以寫入第一個子數組,而另一個線程寫入第二個子數組。
鎖定Collections.synchronizedMap()
和ConcurrentHashMap
之間的區別如下:
如果多個線程經常訪問Collections.synchronizedMap()
,則會有很多爭用,因為每個方法都使用共享鎖進行同步(即,如果線程X調用Collections.synchronizedMap()
上的方法,則所有其他線程將是阻止調用Collections.synchronizedMap()
上的任何方法,直到線程X從它調用的方法返回為止。
ConcurrentHashMap
具有可變數量的鎖(默認值為16),每個鎖都保護ConcurrentHashMap
的一段鍵。 因此對於具有160個鍵的ConcurrentHashMap
,每個鎖將保護10個元素。 因此,對密鑰( get
, put
, set
等)進行操作的方法僅鎖定對在密鑰位於同一段中的密鑰上操作的其他方法的訪問。 例如,如果線程X調用put(0, someObject)
,然后線程Y調用put(10, someOtherObject)
那些調用可以並發執行,並且線程Y不必等待線程X從put(0, someObject)
返回put(0, someObject)
。 下面提供一個例子。
此外,某些方法(如size()
和isEmpty()
根本不受保護。 雖然這允許更大的並發性,但這意味着它們不是非常一致的(它們不會反映同時發生變化的狀態)。
public static void main(String[] args) {
ConcurrentHashMap<Integer, Object> map = new ConcurrentHashMap<>(160);
new Thread(new Runnable() {
@Override
public void run() {
map.put(0, "guarded by one lock");
}
}.start();
new Thread(new Runnable() {
@Override
public void run() {
map.put(10, "guarded by another lock");
}
}.start();
new Thread(new Runnable() {
@Override
public void run() {
// could print 0, 1, or 2
System.out.println(map.count());
}
}.start();
}
這里的關鍵概念是“桶”。 相反,對整個哈希表使用全局鎖,它為每個桶使用一個小鎖。 它也類似於桶排序,可以提高排序復雜性。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.