这是我参与 8 月更文挑战的第 8天,活动详情查看: 8月更文挑战
书接上文的parallelStream流式并行处理造成的问题,parallelStream流式陷阱,这里我说过,在并行流之前加了一个重量级锁,它就是用Collections.synchronizedMap来进行处理的
你可能会问为什么是Collections.synchronizedMap而不是ConcurrentHashMap,不急,我们先来说下Collections.synchronizedMap;
Collections.synchronizedMap他是一个大锁(重量级锁),在用它包裹起来的集合,该集合所有的数据都会被上锁,类似的还有Collections.synchronizedList等集合,他们都是一种情况,我们来看下官方文档给的解释:
Map m = Collections.synchronizedMap(new HashMap());
-
synchronizedMap代码块包裹的是m的所有数据,而不是迭代的单数据
-
并发情况下修改数据可能会报出ConcurrentModificationException异常,并发修改快速失败;
-
传入的是序列化数据返回的也会是序列化的
是的,synchronized包裹住所有数据,那么ConcurrentHashMap呢?他又是个什么玩意?
它是一个段锁,或者bucket包,将我们的所有数据一段一段上锁,在你操作这段数据的时候,另一个线程依然可以操作其他段的数据,虽然synchronized现在是一个可升级锁,在数据处理上速度提升了很多,但不可否认它锁住了所有数据,那ConcurrentHashMap有什么注意点,或者为什么线程安全和效率兼顾的情况下会选择它呢?我们总结一下官方给的说明
-
不会保留传入的Map中元素的顺序,存储类似于HashMap
-
ConcurrentHashMap如果一个线程尝试修改它,而另一个线程对其进行迭代不会触发ConcurrentModificationException异常
-
对数据加锁是多段锁
简单理解就是Collections.synchronizedMap锁的是整个对象,ConcurrentHashMap锁住的是对象的部分内存;
那么我们平时应该用哪个呢,比如说你的数据对于并发的要求不是很高,但是对数据同步有很高要求,那么我们建议用Collections.synchronizedMap,如果你对并发有要求,并且可以对部分数据的读的实时性要求没那么大,那么就用ConcurrentHashMap,当然我还是更加倾向于ConcurrentHashMap,直接new就可以了,没必要再包装一下;
另外最后说一句题外话:这两个都是线程安全的,用哪个保证线程安全都没有错的,值得注意的Collections.synchronizedMap就是典型的装潢模式,想看设计模式的装潢模式的,可以看看这个源码学习一下;