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

摘要:
ConcurrentHashMap如何确保线程安全?1.HashTable在高并发场景中表现不佳;2.HashMap不是线程安全容器;3.虽然同步包装器使用同步方法来快速提高一些性能,但它仍然不适合高并发场景中的性能要求;接下来,回答以下问题:ConcurrentHashMap如何确保线程安全=null)returnoldVal;中断;}}addCount;returnnull;}本节回答了java提供的并发容器的分类,以及ConcurrentHashMap如何确保java7和java8中的线程安全。

image.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可能不太准确。

数据结构如下图:

image.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<K,V>[] tab = table;;) {
        Node<K,V> 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<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 != 0) {
                if (binCount >= TREEIFY_THRESHOLD)
                    treeifyBin(tab, i);
                if (oldVal != null)
                    return oldVal;
                break;
            }
        }
    }
    addCount(1L, binCount);
    return null;
}

小结


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


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

image.png

原创不易,转载请注明出处。

免责声明:文章转载自《面试刷题10:ConcurrentHashMap如何保证线程安全?》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Unity3D 解决用Unity导出的Android工程在6.0及以上设备会弹出一串权限对话框的问题SQLite 如何设置自增字段下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

哈希表(hash)

散列表(Hash table,也叫哈希表),是根据键(Key)而直接访问在内存储存位置的数据结构。也就是说,它通过计算一个关于键值的函数,将所需查询的数据映射到表中一个位置来访问记录,这加快了查找速度。这个映射函数称做散列函数,存放记录的数组称做散列表。 (来自维基百科) 其中前边说到的离散化也是一种特殊的哈希方式,只不过离散化注重保序性,因此使用二分查找...

php Redis函数使用总结(string,hash,list, set , sort set )

  对于:string, set , sort set , hash 的增,改操作,是同一个命令,但是把它当改操作时,及时成功返回值依旧为0 对于:list结构来说,增删改查自有一套方法。   1 <?php 2 /*1.Connection*/ 3 $redis = new Redis(); 4 $redis-...

黑客如何破解验证码机制

    所谓验证码,就是将一串随机产生的数字或符号,生成一幅图片,图片里加上一些干扰象素(防止OCR),由用户肉眼识别其中的验证码信息。   输入表单提交网站验证,验证成功后才能使用某项功能。不少网站为了防止用户利用机器人自动注册、登录、灌水,都采用了 验证码技术。   很多验证码实现都有问题。比如直接给出用验证码在网页和cookies中。   验...

windows环境下为php打开ssh2扩展

安装步骤 1. 下载 php extension ssh2下载地址http://windows.php.net/downloads/pecl/releases/ssh2/0.12/ 根据自己PHP的版本去下载,我使用的是线程安全的,所以下载的是php_ssh2-0.12-5.4-ts-vc9-x86.zip 注意:ts是线程安全的,nts是线程不安全的,...

CVE-2020-1472相关杂谈

CVE-2020-1472是微软八月修复的一个严重的权限提升漏洞(并于昨天2020年9月15日secura发布了相关的漏洞细节,随后相关exp被构造发布),通过Netlogon 远程协议 (MS-NRPC) 建立与域控制器连接安全通道时,存在特权提升的利用点,该漏洞的CVSS分高达10分,攻击者只需要在内网中有一个立足点,就可以远程获取域控的管理员权限。...

redis中的hash、列表、集合操作

一、hash操作 数据结构:key:{k1:v1, k2:v2, k3:v3} 类似Python中的字典 如:info : {name: lina, age: 22, sex: F} hset key k1 v1 设置/创建(字典) hget key k1 获取key1 中 k1对应的值 批量设置获取 hmset key k2 v2 k3 v3 同时...