大家一切顺利~
文章目录
- 前言
- HashTable, HashMap, ConcurrentHashMap 之间的区别
前言
本篇主要内容如标题
HashTable, HashMap, ConcurrentHashMap 之间的区别
1.ConcurrentHashMap最大优化之处是相比于HashTable,ConcurrentHashMap大大缩小了所冲突的范围,把一把大锁切成了多把小锁.
HashTable的做法是直接在方法上加synchronized,等于直接在this上加锁,只要操作哈希表上的任何元素,都可能产生锁冲突.但实际上,有些元素在并发操作中不会产生锁冲突,不需要这把大锁.
如下图是一个数组,数组的每个元素是一个链表,两个线程分别修改结点1,2,由于1,2有1.next = 2的关系,所以两个线程同时修改这两个节点会有问题,需要锁去控制.但若两个线程同时修改结点3,4,就不会有问题,不需要锁去控制.
HashTable针对整个数组加一把锁,同时修改任意两个元素都会产生锁冲突.
ConcurrentHashMap是数组中每个链表都有自己的锁,两个线程操作同一链表中的元素会有锁冲突,针对不同链表上的元素就没有锁冲突.
2.ConcurrentHashMap有一个激进的操作,只针对写操作加锁,不对读操作加锁.两个线程同时对一个变量进行读操作或者一个读一个写都不会有锁冲突.
但这样会出现脏读的问题,即一个线程正在读一个变量,而另一线程正在修改这个变量,读到的变量可能是修改之前的数据,是不准确的数据.
解决这个问题的办法是,对可能会被修改的变量进行volatile修饰,将这个变量的写操作设为原子操作,写完之后才允许别的线程去读取这个变量.
3.ConcurrentHashMap内部充分利用了CAS机制,可进一步削减加减操作的数目,比如维护元素个数.
4.进行扩容时,HashMap和HashTable都是先创建更大的数组空间,把旧数组上的每个元素搬到新数组上.所以,当数组满需要扩容的时候,再次put(),会发现这次put非常卡.
ConcurrentHashMap扩容方法是,创建新数组,旧数组先保留,之后每次进行put()操作时,把要添加的元素put到新数组上,把旧数组上的一部分元素搬到新数组上.进行get()操作的时候,旧数组和新数组都要去查询.每次move()的时候,把元素直接删除即可.
等到旧数组上的元素全都被搬到新数组上,就可以释放
旧数组了.
本文结束