如何保证线程安全有序性_面试刷题10:ConcurrentHashMap如何保证线程安全?

c577f72b1abb6e20fefefbc8fdcb1037.png


集合框架中的HashTable,Stack,以及同步包装集合在高并发场景下都非常低效,java提供了并发包应对高并发场景。


我是李福春,我在准备面试,今天的问题是?


java提供了哪些并发的容器?ConcurrentHashMap如何保证线程安全?

java体系中的并发容器


java体系中有如下同步容器:


1, HashTable,Stack 同步容器,内部使用sychronized关键字保证同步操作;


2,同步包装器Collections.synchronizedMap(),内部也使用sychronized关键字保证同步操作;

3,并发包提供的同步容器,比如ConcurrentHashMap , CopyOnWriteArrayList , ArrayBlockingQueue,SynchronizedQueue

ConcurrentHashMap的同步分析


为何会出现ConcurrenHashMap?


1, HashTable在高并发场景下性能低下;


2,HashMap 不是线程安全的容器;


3,同步包装器虽然使用同步方法快提升了部分性能,但是还是不适合高并发场景下的性能需求;


接下来回答问题,ConcurrentHashMap如何保证线程安全?

java7


java7版本使用的是分离锁(segment)实际上是一种再入锁(RetrantLock)来保证线程安全;


segment的数量是concurrentLevel决定,默认值是16;


扩容的时候是针对单个segment扩容的,写操作也是,修改数据的时候锁定的部分,所以比较高效;


但是后去size可能不太准确。

数据结构如下图:

d5758301689fc9182140f80ae35eaf3f.png

java8


java8中segment依然存在,不过不起结构上的作用,只起到保证序列化的兼容性。


内部使用volatile来保证数据存储的可见性;

利用CAS操作,在特定场景下进行无锁并发操作,内部的锁实际用的是syncronized;


因为在jdk8中,syncronized已经得到性能的优化,并且对比再入锁可以减少内存消耗。


见代码:

final V putVal(K key, V value, boolean onlyIfAbsent) { if (key == null || value == null) throw new NullPointerException();    int hash = spread(key.hashCode());    int binCount = 0;    for (Node[] tab = table;;) {        Node f; int n, i, fh; K fk; V fv;        if (tab == null || (n = tab.length) == 0)            tab = initTable();        else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {            // 利用CAS去进行无锁线程安全操作,如果bin是空的            if (casTabAt(tab, i, null, new Node(hash, key, value)))                break;         }        else if ((fh = f.hash) == MOVED)            tab = helpTransfer(tab, f);        else if (onlyIfAbsent // 不加锁,进行检查                 && fh == hash                 && ((fk = f.key) == key || (fk != null && key.equals(fk)))                 && (fv = f.val) != null)            return fv;        else {            V oldVal = null;            synchronized (f) {                   // 细粒度的同步修改操作...                 }            }            // Bin超过阈值,进行树化            if (binCount != 0) {                if (binCount >= TREEIFY_THRESHOLD)                    treeifyBin(tab, i);                if (oldVal != null)                    return oldVal;                break;            }        }    }    addCount(1L, binCount);    return null;}

小结


本节回答了java提供的并发容器分类,以及ConcurrentHashMap在java7,java8中的是如何保证线程安全的。


面试官喜欢问分离锁,画一下数据结构就明确了。

3c399f95b4b9bd57e44a82ed67ad16fc.png

原创不易,转载请注明出处,让我们互通有无,共同进步,欢迎多沟通交流。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值