Java常用併發容器總結(二)
ConcurrentHashMap
1.介紹
ConcurrentHashMap是一個高效併發的HashMap,它採用了減小鎖粒度的手段,內部進一步細分成了若干個小的HashMap,稱為Segment段。預設情況下,一個ConcurrentHashMap被分為16個段。多ConcurrentHashMap操作時,並不是將整個ConcurrentHashMap加鎖,而是首先根據hashCode定位到要操作的Segment,然後對該段進行加鎖。在多執行緒環境下,如果多個執行緒操作同一個ConcurrentHashMap的不同Segment,可以做到真正的並行,大大提高了效率。
2.程式碼分析
下面以ConcurrentHashMap的put()方法為例,分析ConcurrentHashMap的操作策略:
public V put(K key, V value) {
Segment<K,V> s;
if (value == null)
throw new NullPointerException();
//計算key的hashCode
int hash = hash(key);
//根據hashCode,找到要進行操作的段
int j = (hash >>> segmentShift) & segmentMask;
if ((s = (Segment<K,V>)UNSAFE.getObject
(segments, (j << SSHIFT) + SBASE)) == null)
s = ensureSegment(j);
//對該段進行put
return s.put(key, hash, value, false);
}
可以看出,對ConcurrentHashMap的put操作,可以將粒度減小為對某一個Segment的操作,大大減小了鎖的競爭,提高併發效率。
但是,減小鎖的粒度引入了一個新的問題,當系統需要獲得全域性鎖時,消耗的資源較多。以size()方法為例:
public int size() {
final Segment<K,V>[] segments = this.segments;
int size;
boolean overflow;
long sum;
long last = 0L;
int retries = -1;
try {
for (;;) {
if (retries++ == RETRIES_BEFORE_LOCK) {
for (int j = 0; j < segments.length; ++j)
//在這裡,需要多每一個Segment分別加鎖
ensureSegment(j).lock();
}
sum = 0L;
size = 0;
overflow = false;
for (int j = 0; j < segments.length; ++j) {
Segment<K,V> seg = segmentAt(segments, j);
if (seg != null) {
//計算size總數
sum += seg.modCount;
int c = seg.count;
if (c < 0 || (size += c) < 0)
overflow = true;
}
}
if (sum == last)
break;
last = sum;
}
} finally {
if (retries > RETRIES_BEFORE_LOCK) {
for (int j = 0; j < segments.length; ++j)
//這裡再分別釋放每一段的鎖
segmentAt(segments, j).unlock();
}
}
return overflow ? Integer.MAX_VALUE : size;
}
可以看出,在高併發的場景下,ConcurrentHashMap的size()方法的效率要明顯低於HashMap。
3.適用場景
簡單地說,如果想在高併發的場景下使用HashMap,那麼ConcurrentHashMap將是一個很好的選擇。
相關文章
- 併發容器與框架——併發容器(二)框架
- 通俗易懂,JDK 併發容器總結JDK
- Java併發容器Java
- Java併發(9)- 從同步容器到併發容器Java
- Java同步容器和併發容器Java
- Java 容器系列總結Java
- Java併發思考-導讀&總結篇Java
- Java併發指南14:Java併發容器ConcurrentSkipListMap與CopyOnWriteArrayListJava
- 併發程式設計(二)——併發類容器ConcurrentMap程式設計
- Java併發程式設計-鎖及併發容器Java程式設計
- java併發包學習系列:jdk併發容器JavaJDK
- Java併發佇列與容器Java佇列
- Java 併發程式設計學習總結Java程式設計
- 詳解Java 容器(完結篇)——詳解容器的設計模式、List、Map、併發容器Java設計模式
- java常用Api總結JavaAPI
- 詳解Java 容器(第⑤篇)——容器原始碼分析 - 併發容器Java原始碼
- java併發程式設計:同步容器Java程式設計
- 【java學習之容器總結】Java
- Java容器型別使用總結Java型別
- Java併發程式設計實戰總結 (一)Java程式設計
- Java知識點總結(Java容器-List)Java
- Java知識點總結(Java容器-Vector)Java
- Java知識點總結(Java容器-Set)Java
- 常用Java集合類總結Java
- 【搞定 Java 併發面試】面試最常問的 Java 併發基礎常見面試題總結!Java面試題
- 【Java併發專題】27篇文章詳細總結Java併發基礎知識Java
- 併發總結累積
- 開源容器 Podman 常用命令總結!
- 《java併發程式設計的藝術》併發容器和框架Java程式設計框架
- Java高併發秒殺系統【觀後總結】Java
- Java併發小結01Java
- Java併發容器,底層原理深入分析Java
- 併發容器J.U.C -- AQS同步元件(二)AQS元件
- 執行緒併發總結執行緒
- Java 容器相關知識全面總結Java
- java總結第二週Java
- Java 多執行緒 | 併發知識問答總結Java執行緒
- 【Java併發程式設計】synchronized相關面試題總結Java程式設計synchronized面試題