首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >面试刷题10:ConcurrentHashMap如何保证线程安全?

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

作者头像
李福春
发布2025-07-01 16:30:56
发布2025-07-01 16:30:56
2640
举报
图片
图片

    集合框架中的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可能不太准确。

数据结构如下图:

图片
图片

java8

java8中segment依然存在,不过不起结构上的作用,只起到保证序列化的兼容性。 内部使用volatile来保证数据存储的可见性; 利用CAS操作,在特定场景下进行无锁并发操作,内部的锁实际用的是syncronized; 因为在jdk8中,syncronized已经得到性能的优化,并且对比再入锁可以减少内存消耗。 见代码:

代码语言:javascript
复制
final V putVal(K key, V value, boolean onlyIfAbsent) { if (key == null || value == null) throw new NullPointerException();
    int hash = spread(key.hashCode());
    int binCount = ;
    for (Node<K,V>[] tab = table;;) {
        Node<K,V> f; int n, i, fh; K fk; V fv;
        if (tab == null || (n = tab.length) == )
            tab = initTable();
        else if ((f = tabAt(tab, i = (n - ) & hash)) == null) {
            // 利用CAS去进行无锁线程安全操作,如果bin是空的
            if (casTabAt(tab, i, null, new Node<K,V>(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 != ) {
                if (binCount >= TREEIFY_THRESHOLD)
                    treeifyBin(tab, i);
                if (oldVal != null)
                    return oldVal;
                break;
            }
        }
    }
    addCount(1L, binCount);
    return null;
}

小结

本节回答了java提供的并发容器分类,以及ConcurrentHashMap在java7,java8中的是如何保证线程安全的。 面试官喜欢问分离锁,画一下数据结构就明确了。

图片
图片
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-04-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 李福春持续输出 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Java体系中的并发容器
  • ConcurrentHashMap的同步分析
    • java7
    • java8
  • 小结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档