ConcurrentHashMap && Hashtable#
ConcurrentHashMap 是如何实现线程安全的 ?#
JDK1.5 中的实现#
使用
Segment(extends ReentrantLock)
来实现
使用分段锁技术
, 将 ConcurrentHashMap 将锁一段一段的存储,然后给每一段数据配一把锁(segment),当一个线程占用一把锁(segment)访问其中一段数据的时候,其他段的数据也能被其它的线程访问,默认分配 16 个 segment, 默认比 Hashtable 效率提高 16 倍
JDK1.8 中的实现#
采用
CAS
和synchronized
来保证并发安全
JDK8 中的实现也是锁分离的思想,它把锁分的比segment(JDK1.5)
更细一些,只要 hash 不冲突,就不会出现并发获得锁的情况。它首先使用无锁操作CAS
插入头结点,如果插入失败,说明已经有别的线程插入头结点了,再次循环进行操作 (类似自旋锁)。如果头结点已经存在,则通过synchronized获得头结点锁
,进行后续的操作,性能比 segment 分段锁又再次提升
Hashtable#
Hashtable 也是线程安全的的一种键值对的数据结构
和 HashMap 比较:#
- Hashtable 在 JDK1.0 就有了,HashMap 产生于 JDK1.2
- Hashtable 继承自 Dictionary 类 (已废弃), HashMap 是继承自 AbstractMap 类
- Hashtable 既不支持 Null key 也不支持 Null value,HashMap 中,null 可以作为键,这样的键只有一个;可以有一个或多个键所对应的值为 null
- Hashtable 是线程安全的,它的每个方法中都加入了 Synchronize 方法,HashMap 不是线程安全的
- Hashtable、HashMap 都使用了 Iterator,不过由于历史原因,Hashtable 还使用了 Enumeration 的方式
- Hashtable 默认的初始大小为 11,之后每次扩充,容量变为原来的 2n+1。HashMap 默认的初始化大小为 16。之后每次扩充,容量变为原来的 2 倍
- 计算 hash 值的方法不同: Hashtable 直接使用对象的 hashCode, 而 HashMap 还使用了扰动函数处理
和 Collections.synchronizedMap () 的区别#
synchronizedMap
是 Collections 的私有静态内部类,可以通过Collecitons.synchronizedMap(Map)
方法获取一个 synchronizedMap 向上转型为 Map 对象
对比分析:
- Hashtable 是对所有方法通过 synchronized 关键字加锁
- 有一个 Object 类型 mutext 互斥对象成员,对存在线程安全的方法使用 synchronize 关键字对 mutex 进行加锁