【多线程】HashMap、HashTable和ConcurrentHashMap的联系

在学习多线程的时候,有一些与线程安全相关的数据结构也要进行分类。

HashMap:线程不安全。在某个线程进行调用的时候,如果另一个线程也调用同一个HashMap的话,会发生一系列线程安全问题。

HashTable:线程安全。在源码中,HashTable里的put和get等等方法是被synchronized进行修饰的,也意味着其进行多线程任务的时候是安全的。

 

 

ConcurrentHashMap:线程安全。在源码中可以发现,ConcurrentHashMap中的方法get等读取数据的方法并没有加锁,但是put和replace等等修改哈希表中的键值对的方法进行了加锁,而且不是直接加锁加在整个方法上,而是在内部进行加锁:
 

 上图中get方法作为读取操作并没有加锁。

 

 上图中put方法作为修改操作,调用了putVal方法,而putVal方法进行了内部加锁操作。

 同理,作为修改操作的clear方法也进行了加锁操作。

总结:

<1>HashMap为线程不安全的哈希表,多线程调用时会发生线程不安全问题。

<2>HashTable为线程安全的哈希表,虽然进行了加锁操作,但是是直接加锁给整个方法,这样子里面一些不会发生线程安全问题的操作也会被加锁,当进行多线程任务的时候发生锁竞争的概率很高,因此效率很低。

<3>ConcurrentHashMap为线程安全的哈希表,也进行了加锁,但是并不像HashTable一样直接加在方法上,而是在方法内部的某一些地方进行加锁,比如说,在Java7版本,ConcurrentHashMap将键值是链表进行存储,然后加锁操作是对好几个链表进行加锁,也叫做锁分段,在Java8中,是对一条条链表进行加锁,进一步提高了多线程调用时候的效率,降低锁冲突的概率。还有,ConcurrentHashMap中对读取操作并不进行加锁,因为读取操作并没有修改里面的内容。当进行扩容线程的时候,并不是直接建立一个数组加链表直接复制过去,而是在需要扩容的时候,先建立新的数组,然后每次有操作ConcurrentHashMap的时候,就将几个元素搬运过去,此时新老数组同时存在,在扩容期间查找操作会查找新数组和老数组里面的元素的值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值