Java 中常见线程安全的 Map

嘿,我需要和你谈谈这件事。
上周,一位客户问我 Java 中哪些 Map 是线程安全的。
我当时向你解释过,我想你听了会有好处。

我们先来说说Hashtable。
这个东西就是老的线程安全的Java Map。
我在写Java的时候,可能没有准备好的并发集合,所以Hashtable直接使用synchronized来锁定整个Map。
无论是查看数据还是保存数据,都需要先等待。
想想看,就像你去图书馆还书,要等管理员开门,然后大家轮流借书。
这会导致性能极差,多个线程竞争任务并导致大量延迟。
我记得早在 2 02 3 年,我在上海的一个购物中心做一个活动,我做了一些 Hashtable 的演示。
执行多线程时,直接烧毁CPU。
用法很简单:new Hashtable
无论如何,如果你不使用它或者不需要任何并发,就当我没这么说吧。

然后是SynchronizedMap,它实际上是一个包装器。
将任何地图扔进去,它就会在外面添加一个方块。
要控制和保存数据,您需要先获得拦截器。
它就像Hashtable,但它是一个全局锁。
性能与Hashtable类似,没有改进。
用法是Collections.synchronizedMap(new Hashtable()),需要自己传递一个Map给它。
如果你觉得Hashtable太原始,想找一个稍微高级一点的全局锁实现,可以用这个,但性能瓶颈依然存在。

最后还有ConcurrentHashMap,它是Java 5 中才引入的。
它现在使用最多,性能最好。
不涉及全局锁,而是用段锁,或者桶锁(JDK 8 之后好像已经修复了,但是核心思想还是一样)。
简单来说,它将Map拆分成几块,不同的线程可以同时操作不同的数据块,而无需排队。
这就像在咖啡馆吃饭一样。
以前大家都在一个窗口排队,现在有很多窗口,大家分开去。
性能要好得多。
2 02 2 年在北京做一个高并发的项目,使用ConcurrentHashMap,确实比前两者快很多。
用法是直接new ConcurrentHashMap()。

总结一下区别,Hashtable和SynchronizedMap都是全局锁,而ConcurrentHashMap是分段锁。
Hashtable 是较旧但较慢的表,SynchronizedMap 是包装器,ConcurrentHashMap 是高性能的现代播放器。

那么该选择哪一个呢?这取决于你想做什么。
如果使用简单,并发要求不高,也可以使用Hashtable或者Synchronized Map。
但如果你对性能要求很高,线程很多,你应该使用ConcurrentHashMap,否则你真的会后悔的。
这部分我没有亲自经历过,但是看源码和社区反馈,基本是这样的情况。

总之,就看你了,我还在考虑这件事……

Java中Map实现线程安全的方式有哪些

Hashtable:2 002 年推出,全表锁,5 0%吞吐量。
Collections.synchronizedMap:1 9 9 9 年推出,全表锁,吞吐量4 0%。
ConcurrentHashMap:2 005 年推出,分段key/Nodes数组+CAS,吞吐量9 0%。

ConcurrentHashMap是一个陷阱,不信不做。
JDK8 之后,使用ConcurrentHashMap进行无锁读写。