网站首页 > java教程 正文
上次有小伙伴在评论中说能不能说一下concurrenthashmap在1.7和1.8中的区别,这次就给大家发出来。有不对的地方还请指正。
1. 1.8相比1.7,主要改变为:
a. 去除Segment+HashEntry+UnSafe的实现,改为Synchronized+CAS+Node+UnSafe的实现,其实Node和HashEntry的内容一样,但是HashEntry是一个内部类。用Synchronized+CAS代替Segment,这样锁的粒度更小了,并且不是每次都要加锁了,CAS尝试失败了再加锁。
b. Put()方法中初始化数组大小时。1.8不用加锁,因为用了个sizeCtl变量,将这个变量置为-1,就表明table正在初始化。
2. 下面简单介绍几个主要的方法的一些区别:
a. Put()方法
i. 1.7中的实现:
ConCurrentHashMap和HashMap的put方法实现基本类似,所以主要讲一下为了实现并发性,ConCurrentHashMap 1.7有了什么改变:
1) 需要两次定位(segment(i),segment中的table[i])
由于引入了segment的概念,所以需要
a) 先通过key的rehash值的高位和segments数组大小-1相与得到再segments中的位置
b) 然后再通过key的rehash值和table数组大小-1相与得到在table中的位置;
2) 没获取到segment锁的线程,没有权利进行put操作,不像是HashTable一样去挂起等待,而是会去做一下put操作前的准备:
a) table[i]的位置(你的值需要put到哪个桶中)
b) 通过首节点first遍历链表找有没有相同key
c) 在进行上述步骤的期间还不断自旋获取锁,超过64次线程挂起!
ii. 1.8中的实现:
1) 先拿到rehash值定位,拿到table[i]的首节点first,然后
a) 如果为nul,通过CAS的方式把value put进去
b) 如果为非null,并且first.hash == -1,说明其他线程在扩容,参与一起扩容;
c) 如果非null,并且first.hash != -1,Synchronized锁住first节点,判断是链表还是红黑树,遍历插入。
b. get()方法
i. 1.7中的实现:
1) 由于变量value是由volatile修饰的,Java内存模型中的happen before规则保证了对于volatile修饰的变量始终是写操作先于读操作的,并且还有volatile的内存可见性保证修改完的数据可以马上更新到主存中,所以能保证在并发情况下,读出来的数据是最新额数据;
2) 如果get()到的是null值才去加锁。
ii. 1.8中的实现
1) 与1.7类似
c. resize()方法
i. 1.7中的实现:
1) 和HashMap中的resize()没多大区别,都是在put元素时去做的扩容,所以在1.7中的实现是获得了锁之后,在单线程中去做扩容(1.new个2倍数组,2.遍历old数组节点搬去新数组);
ii. 1.8中的实现:
1) 1.8的扩容支持并发迁移节点,从old数组的尾部开始,如果该桶被其他线程处理过了,就创建一个ForwardingNode放到该桶的首节点,hash值为-1,其他线程判断hash值为-1后就知道该桶被处理过了。
d. 计算size
i. 1.7中的实现:
1) 先采用不加锁的方式,计算两次,如果两次结果一样,说明是正确的,返回;
2) 如果两次结果不一样,则把所有segment锁住,重新计算所有segment的count的和。
ii. 1.8中的实现:
由于没有segment的概念,所以只需要用一个baseCount变量来记录ConcurrentHashMap当前节点的个数。
1) 先尝试通过CAS修改baseCount;
2) 如果多线程竞争激烈,某些线程CAS失败,那就产生过hi将CELLSBUSY置为1,成功则可以把baseCount变化的次数暂存到一个数组counterCells中,后续数组counterCells的值会加到baseCount中;
3) 如果CELLSBUSY置1失败又会反复进行CASbaseCount和CAScounterCells数组。
想获取完整面试题及答案的同学请点赞、关注并转发。私信楼主:“Java面试题”获取完整资料,更有超全spring、jvm、linux、docker等电子书相送。
- 上一篇: Java从入门到精通到全栈
- 下一篇: Java多线程系列(四):4种常用Java线程锁的特点...
猜你喜欢
- 2024-12-11 Java多线程系列(四):4种常用Java线程锁的特点...
- 2024-12-11 Java从入门到精通到全栈
- 2024-12-11 Java面试必考问题:Java方法区存储了哪些数据
- 2024-12-11 Java异常处理和最佳实践(含案例分析)
- 2024-12-11 时代变了,对比完Rust,发现Java差一大截!
- 2024-12-11 高并发编程系列:4大Java线程锁全面详解
- 2024-12-11 AMD 锐龙7 2700/锐龙5 2600评测:搭配这个黑科技,游戏变得更快
- 2024-12-11 用云存储30分钟快速搭建APP,你信吗?
- 2024-12-11 Java当中的一些奇技淫巧
- 2024-12-11 Java 注解(Annotation)
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)