如何保证集合是线程安全的?ConcurrentHashMap如何实现高效的线程安全?

问题:

  • 如何保证集合是线程安全的?
  • ConcurrentHashMap如何实现高效的线程安全?

    知识点:

  1. 为什么需要ConcurrentHashMap?
    Hashtable比较低效,所有线程公用同一把锁,效率低下。Collections工具类提供的Map方法,大同小异,源码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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();
}
}

高并发时候,容易始HashMap死循环导致CPU占用100%。可参考不正当使用HashMap导致cpu 100%的问题追究
HashMap 死循环的探究

  1. ConcurrentHashMap,篇幅太长,后续有专门文章分析。

回答问题

Java提供了不同层面的线程安全支持,在传统的框架内部,除了Hashtable等同步容器,还提供了所谓的同步包装器,我们可以调用Collecions工具的同步方法,来获取一个同步的包装容器(如:Collections.synchronizedMap),但是他们都是利用非常粗粒度的处理方式,在高并发的时候,性能比较低下。

另外,更加普遍的选择是利用并发包提供的线程安全容器类,它提供了:

具体保证线程安全的方式,包括从有简单的synchronize方式,到基于更加精细化的,比如基于分离锁实现的ConcurrentHashMap等并发实现等。具体选择要看开发的场景需求。总得来说,并发包提供的容器通用场景,远优于早期的简单的同步实现。
自己项目中使用代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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;
}
}

参考:

声明:此为原创,转载请联系作者


作者:微信公众号添加公众号-遛狗的程序员 ,或者可以扫描以下二维码关注相关技术文章。

qrcode_for_gh_1ba0785324d6_430.jpg

当然喜爱技术,乐于分享的你也可以可以添加作者微信号:

WXCD.jpeg

文章目录
  1. 1. 问题:
  2. 2. 知识点:
  3. 3. 回答问题
|