ConcurrentHashMap && Hashtable

ConcurrentHashMap是如何实现线程安全的 ?

JDK1.5中的实现

使用Segment(extends ReentrantLock)来实现
使用分段锁技术,将ConcurrentHashMap将锁一段一段的存储,然后给每一段数据配一把锁(segment),当一个线程占用一把锁(segment)访问其中一段数据的时候,其他段的数据也能被其它的线程访问,默认分配16个segment, 默认比Hashtable效率提高16倍

JDK1.8中的实现

采用CASsynchronized来保证并发安全
JDK8中的实现也是锁分离的思想,它把锁分的比segment(JDK1.5)更细一些,只要hash不冲突,就不会出现并发获得锁的情况。它首先使用无锁操作CAS插入头结点,如果插入失败,说明已经有别的线程插入头结点了,再次循环进行操作(类似自旋锁)。如果头结点已经存在,则通过synchronized获得头结点锁,进行后续的操作,性能比segment分段锁又再次提升

Hashtable

Hashtable 也是线程安全的的一种键值对的数据结构

和HashMap比较:

  1. Hashtable在JDK1.0 就有了, HashMap产生于JDK1.2
  2. Hashtable继承自Dictionary类(已废弃), HashMap是继承自AbstractMap类
  3. Hashtable既不支持Null key也不支持Null value,HashMap中,null可以作为键,这样的键只有一个;可以有一个或多个键所对应的值为null
  4. Hashtable是线程安全的,它的每个方法中都加入了Synchronize方法,HashMap不是线程安全的
  5. Hashtable、HashMap都使用了 Iterator,不过由于历史原因,Hashtable还使用了Enumeration的方式
  6. Hashtable默认的初始大小为11,之后每次扩充,容量变为原来的2n+1。HashMap默认的初始化大小为16。之后每次扩充,容量变为原来的2倍
  7. 计算hash值的方法不同: Hashtable直接使用对象的hashCode, 而HashMap还使用了扰动函数处理

和Collections.synchronizedMap()的区别

synchronizedMap是Collections的私有静态内部类,可以通过Collecitons.synchronizedMap(Map)方法获取一个synchronizedMap向上转型为Map对象

对比分析:

  • Hashtable是对所有方法通过synchronized关键字加锁
  • 有一个Object类型mutext互斥对象成员,对存在线程安全的方法使用synchronize关键字对mutex进行加锁