ConcurrentHashMap的前世今生

引言:
首先需要了解的是内置锁和显示锁
内置锁也叫对象锁,关键字为 synchronized
显示锁就是Lock及其子类
线程不安全的 HashMap
数据结构
     由哈希表实现,数据结构构成为数组+链表+红黑树,解决哈希冲突的方案为拉链法
寻址方式
    通过Integer.highestOneBit算出比指定整数小的最大的2^N值,其实现方法如下。
public static int highestOneBit ( int i) {
i |= (i >> 1 );
i |= (i >> 2 );
i |= (i >> 4 );
i |= (i >> 8 );
i |= (i >> 16 );
return i - (i >>> 1 );
}
     Java8 hashcode计算方式:
public int hashCode () {
int h = hash ;
if ( h == 0 && value . length > 0 ) {
char val [] = value ;

for ( int i = 0 ; i < value . length ; i ++ ) {
h = 31 * h + val [ i ] ;
}
hash = h ;
}
return h ;
}

Java 7基于分段锁的ConcurrentHashMap

ConcurrentHashMap最外层是一个Segment的数组。每个Segment包含一个与HashMap数据结构差不多的链表数组。

同步方式

Segment继承自ReentrantLock,所以我们可以很方便的对每一个Segment上锁。

ReentrantLock内部实现:

CAS状态:通过是否修改成功来判断是否拿到锁
等待队列:
等待队列中的线程都要做park操作

它使用了自旋锁,如果tryLock获取锁失败,说明锁被其它线程占用,此时通过循环再次以tryLock的方式申请锁。如果在循环过程中该Key所对应的链表头被修改,则重置retry次数。如果retry次数超过一定值,则使用lock方法申请锁。

这里使用自旋锁是因为自旋锁的效率比较高,但是它消耗CPU资源比较多,因此在自旋次数超过阈值时切换为互斥锁。

ConcurrentHashMap与HashMap相比,有以下不同点

ConcurrentHashMap线程安全,而HashMap非线程安全

HashMap允许Key和Value为null,而ConcurrentHashMap不允许

HashMap不允许通过Iterator遍历的同时通过HashMap修改,而ConcurrentHashMap允许该行为,并且该更新对后续的遍历可见


Java 8基于CAS的ConcurrentHashMap

1、摒弃了分段锁的方案,而是直接使用数组元素作为锁。
2、 Java 8在链表长度超过一定阈值(8)时将链表(寻址时间复杂度为O(N))转换为红黑树(寻址时间复杂度为O(long(N)))

寻址方式:
    将数组强制初始化为2的幂次,用 hash&(length-1)取模 ,提升了运算速度
同步方式:
    直接使用桶元素作为锁(此处为内置锁)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值