首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往
您找到你想要的搜索结果了吗?
是的
没有找到

ConcurrentHashMap源码(一)

整体流程跟HashMap比较类似,大致是以下几步: (1)如果桶数组未初始化,则初始化; (2)如果待插入元素所在的桶为空,则尝试把此元素直接插入到桶的第一个位置; (3)如果正在扩容,则当前线程一起加入到扩容的过程中; (4)如果待插入的元素所在的桶不为空且不在迁移元素,则锁住这个桶(分段锁); (5)如果当前桶中元素以链表方式存储,则在链表中寻找该元素或者插入元素; (6)如果当前桶中元素以红黑树方式存储,则在红黑树中寻找该元素或者插入元素; (7)如果元素存在,则返回旧值; (8)如果元素不存在,整个Map的元素个数加1,并检查是否需要扩容; 添加元素操作中使用的锁主要有(自旋锁 + CAS + synchronized + 分段锁)。 为什么使用synchronized而不是ReentrantLock? 因为synchronized已经得到了极大地优化,在特定情况下并不比ReentrantLock差。

05

走近concurrentHashMap(JDK1.8)

前面我们学习了HashMap的数据结构,分析了其源码 在本篇文章中与HashMap相同的部分就不在赘述,但是HashMap是线程不安全的容器,在多线程环境下会有线程完全问题,虽然也有线程安全容器Hashtable,但是其通过synchronized修饰方法,通过独占锁的方式锁定类对象,效率不高,所以Java 又提供了线程安全容器ConcurrentHashMap,与HashMap的底层的数据结构相同,ConcurrentHashMap也是采用的“散列表+链表+红黑树”,不过红黑树中存储的不是TreeNode,而是TreeBin。在JDK1.8中 ConcurrentHashMap 大量采用CAS算法,unsafe.compareAndSwapInt(this, valueOffset, expect, update); CAS(compareAndSwap)比较并交换,就是比较valueOffset位置上的值是否等于expect,如果等于的话则返回true,并更新值。(PS:在JDK1.7中采用的是分段锁的方式)。在扩容,设值的过程中大量采用CAS无锁不阻塞的方式支持并发操作,但是是不是就不需要加锁了呢?答案是否定的。

04

Java 8 ConcurrentHashMap源码中竟然隐藏着两个BUG

Java 7的ConcurrenHashMap的源码我建议大家都看看,那个版本的源码就是Java多线程编程的教科书。在Java 7的源码中,作者对悲观锁的使用非常谨慎,大多都转换为自旋锁加volatile获得相同的语义,即使最后迫不得已要用,作者也会通过各种技巧减少锁的临界区。在上一篇文章中我们也有讲到,自旋锁在临界区比较小的时候是一个较优的选择是因为它避免了线程由于阻塞而切换上下文,但本质上它也是个锁,在自旋等待期间只有一个线程能进入临界区,其他线程只会自旋消耗CPU的时间片。Java 8中ConcurrentHashMap的实现通过一些巧妙的设计和技巧,避开了自旋锁的局限,提供了更高的并发性能。如果说Java 7版本的源码是在教我们如何将悲观锁转换为自旋锁,那么在Java 8中我们甚至可以看到如何将自旋锁转换为无锁的方法和技巧。

04

扫码

添加站长 进交流群

领取专属 10元无门槛券

手把手带您无忧上云

扫码加入开发者社群

相关资讯

热门标签

活动推荐

    运营活动

    活动名称
    广告关闭
    领券