作者:爱塔居
专栏:JavaEE
作者简介:大三学生,希望和大家一起进步。
Hashtable和HashMap、ConcurrentHashMap 之间的区别?
HashMap:线程不安全,key允许为null
Hashtable:线程安全,使用synchronized锁Hashtable对象,效率比较低,key不允许为null
ConcurrentHashMap:线程安全,使用synchronized锁每个链表头结点,锁冲突概率低,充分利用CAS机制,优化了扩容方式,key不允许为null。
补充理解
Hashtable只是简单地把关键方法加上了synchronized关键字,这相当于直接针对Hashtable对象本身加锁。
如果多线程访问同一个Hashtable,就会直接造成锁冲突。
size属性也是通过synchronized来控制同步,也比较慢的。
一旦触发扩容,就由该线程完成整个扩容过程,这个过程会涉及到大量的元素拷贝,效率会非常低。
如图:
一个Hashtable只有一把锁。两个线程访问Hashtable中的任意数据都会出现锁竞争。
ConcurrentHashMap
先比于Hashtable做出了一系列的改进和优化
读操作没有加锁,但是使用了volatile保证从内存读取结果,只对写操作进行加锁,加锁的方式仍然是用synchronized,但是不是锁整个对象,而是“锁桶”(用每个链表的头结点作为锁对象),大大降低了锁冲突的概率
充分利用CAS特性,比如size属性通过CAS来更新,避免出现重量级锁的情况。
优化了扩容方式,化整为零
发现需要扩容的线程,只需要一个新的数组,同时只搬几个元素过去。
扩容期间,新老数组同时存在
后续每个操作ConcurrentHashMap的线程,都会参与搬家的过程,每个操作负责搬运一小部分元素。
搬完最后一个元素,再把老数组删掉。
这个期间,插入只往新数组加。
这个期间,查找需要同时查新数组和老数组
ConcurrentHashMap每个哈希桶都有一把锁
只有两个线程访问的恰好是同一个哈希桶上的数据才出现冲突。