Java面试需知--ConcurrentHashMap源码分析

ConcurrentHashMap 是做Java开发必须要掌握的类的用法之一,它弥补了HashTable在并发环境下的性能的不足。引用分离锁的概念,极大地增强了并发性能。

ConcurrentHashMap 存储结构图

图1-1 存储结构

ConcurrentHashMap相比于HashMap新增了一个segments数组,每一个数组分别对应一把锁,ConcurrentHashMap默认情况下这个数组长度为16,即在理想状态下ConcurrentHashMap可以支持16个线程无锁安全访问数据。

举个例子:当有一个线程正在修改segments[0]中的内容时,同时另一个线程要查询的value刚好在segment[2]中,那么segment[2]就不会加锁。

ConcurrentHashMap中的HashEntry内部类

static final class HashEntry<K,V> {    
  final K key;    
  final int hash;    
  volatile V value;    
  final HashEntry<K,V> next; 
...
}

HashMap是以数组加链表的形式存储数据的,ConcurrentHashMap当然也不例外,上面这个是ConcurrentHashMap中用作链表存储的内部类。它除了value 其余变量全部设为final型。

ConcurrentHashMap 中的数据交互

其实分析ConcurrentHashMap最重要的就是分析它是怎么做数据交互的,下面将会依次分析ConcurrentHashMap中数据是怎么存储和删除

1.如何put

由于HashEntry 中 next变量被声明为了final,那么要增加一个新的Entry那就只能从头部添加,如下图:

图1-2 put

它会将新new出来的HashEntry指向原本数组指向的表头元素,然后将数组指向这个类。

2.如何delete

ConcurrentHashMap中删除一个元素可不像传统链表删除一个元素时只需要修改下指针位置那么简单。因为HashEntry中next为final类型,所以位于要删除的元素之前的元素必须要重新new一次,再依次指定next。如下图:

图1-3 delete

ConcurrentHashMap 中的数据脏读

参照图1-3,我们假设一种情况,当线程1想要读取e3的数据,此时读取到了e1位置;而与此同时线程2正在执行删除e3操作,那么就有可能线程2执行完删除操作后,线程1仍然能读取出e3的数据。这就是ConcurrentHashMap中的数据脏读,所以ConcurrentHashMap不适合存储敏感类型的数据。

必须应该了解的Clear方法

首先看一下ConcurrentHashMap中的clear方法的源码

   public void clear() {
        final Segment<K,V>[] segments = this.segments;
        for (int j = 0; j < segments.length; ++j) {
            Segment<K,V> s = segmentAt(segments, j);
            if (s != null)
                s.clear();
        }
    }

它在for循环中逐个去清除Segment下的数据,如果不为空,则调用segment的clear方法。

基于这个方法,有时候就会出现一种比较奇怪的现象:某一个线程刚存进去的key-value,马上就没有了,并且存进去之后并没有任何线程调用clear等类似方法。

结合clear的代码思考一下不难理解,这种情况是在put一个value之前恰好有一个线程调用了clear方法,在这个方法逐个清理segment时,put的这个value刚好保存在了将要被clear但还没有被clear的segment上,所以这个value就会立马被清理掉。

总结

ConcurrentHashMap 是一个并发情况下线程安全的HashMap,但是它的安全并不是那么绝对,在一些特殊情况下仍然有可能会发生数据脏读,数据丢失等情况。所以在我们使用ConcurrentHashMap时一定要了解它的一些特性,这样我们才能在使用它的时候不会产生一些意料之外的问题。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,755评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,369评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,799评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,910评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,096评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,159评论 3 411
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,917评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,360评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,673评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,814评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,509评论 4 334
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,156评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,882评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,123评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,641评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,728评论 2 351

推荐阅读更多精彩内容

  • 数据结构 ConcurrentHashMap 实现并发操作的原理 使用了锁分段技术:ConcurrentHashM...
    tomas家的小拨浪鼓阅读 1,910评论 0 6
  • Java SE 基础: 封装、继承、多态 封装: 概念:就是把对象的属性和操作(或服务)结合为一个独立的整体,并尽...
    Jayden_Cao阅读 2,103评论 0 8
  • 简介 ConcurrentHashMap 是 Java concurrent 包的重要成员。本文将结合 Java ...
    翼徳阅读 1,679评论 3 32
  • 给自己定下的日程行程全部搁置 前两天雄心壮志许下的目标好像也被丢下了 一年又一年没有完成的减肥计划被一顿好吃的又给...
    prayer_ft阅读 180评论 0 0
  • 早起,为孩子准备午餐盒。前夜洗净控干的餐盒,裝上洗净的水果,切块去核的果用保鲜膜仔细包好。备好餐盒,开始烧饭,在炉...
    暗香盈梦阅读 1,409评论 4 6