問題:
- 如何保證集合是線程安全的?
- ConcurrentHashMap如何實現(xiàn)高效的線程安全?
知識點:
- 為什么需要ConcurrentHashMap?
Hashtable比較低效,所有線程公用同一把鎖,效率低下。Collections工具類提供的Map方法,大同小異,源碼如下:
private static class SynchronizedMap<K, V> implements Map<K, V>, Serializable {
private static final long serialVersionUID = 1978198479659022715L;
private final Map<K, V> m;
//劃重點了,利用this作為互斥的mutex
final Object mutex;
private transient Set<K> keySet;
private transient Set<Entry<K, V>> entrySet;
private transient Collection<V> values;
SynchronizedMap(Map<K, V> var1) {
this.m = (Map)Objects.requireNonNull(var1);
this.mutex = this;
}
SynchronizedMap(Map<K, V> var1, Object var2) {
this.m = var1;
this.mutex = var2;
}
public int size() {
Object var1 = this.mutex;
synchronized(this.mutex) {
return this.m.size();
}
}
public boolean isEmpty() {
Object var1 = this.mutex;
//方法不再申明為synchronized方法,但是利用this作為互斥的mutex,大同小異 synchronized(this.mutex) {
return this.m.isEmpty();
}
}
高并發(fā)時候,容易始HashMap死循環(huán)導(dǎo)致CPU占用100%??蓞⒖?a target="_blank" rel="nofollow">不正當(dāng)使用HashMap導(dǎo)致cpu 100%的問題追究,
HashMap 死循環(huán)的探究
- ConcurrentHashMap,篇幅太長,后續(xù)有專門文章分析。
回答問題
Java提供了不同層面的線程安全支持,在傳統(tǒng)的框架內(nèi)部,除了Hashtable等同步容器,還提供了所謂的同步包裝器,我們可以調(diào)用Collecions工具的同步方法,來獲取一個同步的包裝容器(如:Collections.synchronizedMap),但是他們都是利用非常粗粒度的處理方式,在高并發(fā)的時候,性能比較低下。
另外,更加普遍的選擇是利用并發(fā)包提供的線程安全容器類,它提供了:
- 各種并發(fā)容器:比如ConcurrentHashMap、CopyOnWriteArrayList。
- 各種線程安全隊列(Queue/Deque),如ArrayBlockingQueue、synchronousQueue。
- 各種有序容器的線程安全版本。
可參考:Java并發(fā):線程安全的容器:同步和并發(fā) java線程安全的容器有哪些?
具體保證線程安全的方式,包括從有簡單的synchronize方式,到基于更加精細化的,比如基于分離鎖實現(xiàn)的ConcurrentHashMap等并發(fā)實現(xiàn)等。具體選擇要看開發(fā)的場景需求。總得來說,并發(fā)包提供的容器通用場景,遠優(yōu)于早期的簡單的同步實現(xiàn)。
自己項目中使用代碼:
private Map<Promise, ReadableMap> mPictureTakenOptions = new ConcurrentHashMap<>();
private Map<Promise, File> mPictureTakenDirectories = new ConcurrentHashMap<>();
public void takePicture(ReadableMap options, final Promise promise, File cacheDirectory) {
mPictureTakenPromises.add(promise);
mPictureTakenOptions.put(promise, options);
mPictureTakenDirectories.put(promise, cacheDirectory);
if (mPlaySoundOnCapture) {
MediaActionSound sound = new MediaActionSound();
sound.play(MediaActionSound.SHUTTER_CLICK);
}
try {
super.takePicture();
} catch (Exception e) {
mPictureTakenPromises.remove(promise);
mPictureTakenOptions.remove(promise);
mPictureTakenDirectories.remove(promise);
throw e;
}
}
參考:
- 不正當(dāng)使用HashMap導(dǎo)致cpu 100%的問題追究,
- HashMap 死循環(huán)的探究
- Collections工具類中部分源碼
- 極客時間APP核心技術(shù)第十講| 如何保證集合是線程安全的?ConcurrentHashMap如何實現(xiàn)高效的線程安全?
- 自己項目中部分代碼
聲明:此為原創(chuàng),轉(zhuǎn)載請聯(lián)系作者
作者:微信公眾號添加公眾號-遛狗的程序員 ,或者可以掃描以下二維碼關(guān)注相關(guān)技術(shù)文章。

qrcode_for_gh_1ba0785324d6_430.jpg
當(dāng)然喜愛技術(shù),樂于分享的你也可以可以添加作者微信號:

WXCD.jpeg