提问者:小点点

修改并发哈希映射中的值


在ConCurrentHashMap中有分割的概念。如果两个线程试图访问ConCurrentHashMap,这意味着它们被分成两个块,块的默认大小为16。

现在假设在一个场景中,并发HashMap只有两个元素,两个不同的线程出现,thread1尝试修改第一个值,thread2尝试修改第二个值。在这种情况下,并发HashMap是否会进行分段?

现在,在不同的场景中,两个线程都尝试修改相同的值,并发HashMap将如何处理这种情况?通过使用锁定机制还是有其他方法?


共3个答案

匿名用户

并发HashMap有几个桶。键根据其哈希值映射到其中一个桶中。当您添加或检索值时,与该键关联的存储桶将被锁定。

对于你的第一个问题,有两种可能:要么两个键都在同一个桶中,要么它们在不同的桶中。在第一种情况下,一次只有一个线程可以工作——第一个获得锁的线程将抓住它并工作,第二个线程将等待轮到它。在第二种情况下,如果键在不同的桶中,它们将各自获得独立的锁并同时完成它们的工作。

对于您的第二个问题,被锁定的是存储桶,而不是其他任何东西。如果两个线程尝试为同一个键存储两个值,则ConCurrentHashMappromise这两个值中的一个将与该键相关联。即,如果线程A运行map. put("Answers",2);并且线程B运行map.put("Answers",10);,则ConCurrentHashMap将确保映射有效并包含210用于"Answers",但它不会对这两个中的哪一个做出任何promise。

匿名用户

CHM保证这些操作(例如putputIfAbsend等)不会重叠,是的,这是通过锁定完成的。CHM的每个段都有自己的锁,每当您修改该段时都会使用该锁。

(作为参考,正如@Affe指出的,如果您正在修改ConCurrentHashMap中值的内容,CHM不会做——不能做——任何事情来使该线程安全。)

匿名用户

首先,CHM的新实现根本不使用Segments,它仍然使用节点数组,如果给定索引中的节点不存在,并且两个线程试图插入两个具有等于给定索引的hashcode的条目,那么CHM使用CAS,否则如果节点存在,那么CHM使用此节点的第一个元素上的锁来放置新值。CHM中的读取是非阻塞的,并且使用发生在保证之前,借助来自Unsafclass的原子读取。查看我关于CHM的博客了解更多详细信息https://strogiyotec.github.io/pages/posts/chm.html