在ConcurrentHashMap中有分段的概念。这意味着如果两个线程试图访问ConcurrentHashMap,它会被分成两个块,默认大小为16。
现在假设在一个场景中,ConcurrentHashMap只有两个元素,两个不同的线程来了,thread1尝试修改第一个值,而thread2尝试修改第二个值。在这种情况下,ConcurrentHashMap是否会进行分段?
现在在不同的场景中,两个线程都尝试修改ConcurrentHashMap如何处理这种情况的相同值?通过使用锁定机制或还有其他什么?
答案 0 :(得分:4)
ConcurrentHashMap有几个存储桶。密钥根据其哈希值映射到其中一个桶中。添加或检索值时,与该键关联的存储桶将被锁定。
在第一个问题的情况下,有两种可能性:要么两个键都存在于同一个存储桶中,要么它们存在于不同的存储桶中。在第一种情况下,一次只能有一个线程可以工作 - 获取锁定的第一个线程将抓住并工作,第二个线程将轮流等待。在第二种情况下,密钥位于不同的桶中,它们每个都会获得独立的锁并同时完成它们的工作。
对于你的第二个问题, bucket 被锁定,没有别的。如果两个线程尝试为同一个键存储两个值,则ConcurrentHashMap承诺两个值中的一个将与该键相关联。 ie 如果线程A运行map.put("Answers",2);
而线程B运行map.put("Answers",10);
,那么ConcurrentHashMap将确保地图有效且包含2
或10
对于"Answers"
,但它不会对这两者中的哪一个作出任何承诺。
答案 1 :(得分:3)
CHM保证这些操作(例如put
,putIfAbsent
等)不会重叠,是的,这是通过锁定完成的。 CHM的每个部分都有自己的锁,无论何时修改该部分都会被锁定。
(作为参考,正如@Affe指出的那样,如果你正在修改ConcurrentHashMap
中某个值的内容,那么CHM不会这样做 - 不能做 - - 使线程安全的任何事情。)
答案 2 :(得分:0)
首先,CHM的新实现根本不使用细分,如果给定索引中的节点不存在,并且两个线程试图插入两个等于给定哈希码的条目,则仍然使用节点数组索引,然后CHM使用CAS,否则,如果节点存在,则CHM使用对此节点的第一个元素的锁定来放置新值。 CHM中的读取是非阻塞的,并且在通过Unsafe类进行的原子读取的保证下使用即可发生。查看我关于CHM的博客以了解更多详细信息 https://strogiyotec.github.io/pages/posts/chm.html