- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我最近遇到了以下构造
Map<String,Value> map = new HashMap<>();
...
Value getValue(String key) {
synchronized (key.intern()) {
return map.remove(key);
}
}
鉴于intern()
is usually not that fast ,我怀疑这会优于使用 synchronized
、Collections.synchronizedMap(Map)
或 ConcurrentHashMap
。但即使在这种特殊情况下这种构造比所有其他方法更快:这是否正确同步?我怀疑这是线程安全的,因为在重新组织哈希表时可能会发生删除。但即使这行得通,鉴于HashMap javadoc,我怀疑代码会被破坏。状态:
If multiple threads access a hash map concurrently, and at least one of the threads modifies the map structurally, it must be synchronized externally.
最佳答案
这不足以从多个线程安全地访问 HashMap
。事实上,它几乎肯定会破坏某些东西。通过在给定的键上同步,只要不同的线程使用不同的键, map 仍然可以不安全地并发修改。
考虑这三个线程是否试图同时运行:
Thread 1 Thread 2 Thread 3
synchronized("a") { synchronized("a") { synchronized("b") {
map.remove("a"); map.remove("a"); map.remove("b");
} } }
线程 1 和 2 会正确地相互等待,因为它们在同一个对象上同步(Java 实习生字符串常量)。但是线程 3 不受其他线程中正在进行的工作的阻碍,并立即进入其同步块(synchronized block),因为没有其他线程正在锁定 "b"
。现在两个不同的同步块(synchronized block)同时与 map
交互,一切都结束了。不久之后,您的 HashMap
就会损坏。
Collections.synchronizedMap()
正确地使用 map 本身作为同步对象,因此锁定了整个 map ,而不仅仅是正在使用的键。这是防止从多个线程访问的 HashMap
内部损坏的唯一可靠方法。
ConcurrentHashMap
通过内部锁定 map 中所有键的子集,正确地做了我认为您发布的代码试图做的事情。这样,多个线程可以安全地访问不同线程上的不同键,并且永远不会互相阻塞——但如果键恰好在同一个桶中,映射仍然会阻塞。您可以使用 concurrencyLevel
修改此行为构造函数参数。
另请参阅:Java synchronized block vs. Collections.synchronizedMap
顺便说一句,让我们假设 synchronized(key.intern())
是并发访问 HashMap< 的合理方式
。这仍然难以置信容易出错。如果应用程序中只有一个地方未能在某个键上调用 .intern()
,那么一切都可能崩溃。
关于java - HashMap<String,Value>.remove() 通过在 Key 上使用 String.intern() 同步,这是否有效?或者这是损坏的代码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27390281/
我正在使用 .remove() 方法删除一个 html 元素,同时对于这个元素,我有一个事件处理程序,但它没有被触发。为什么会这样呢?这是jsFiddle和代码:HTML Delete I'm goi
所以我尝试从另一篇文章中编写此代码: while(fscanf(orderFile," %49[^;];%d; %49[^\n]",fileName,&seconds,timeValue) == 3)
我正在阅读 Nicolai M.Josuttis 撰写的“The C++ STL. A Tutorial and References”一书,在专门介绍 STL 算法的一章中,作者陈述如下:如果你调用
是否有一种简单的机制来确定 DownloadManager remove() 何时完成,因为它看起来是部分异步的。该函数几乎立即返回下载表中已删除的条目计数,但实际的文件系统管理似乎被插入了某个后台线
我愿意: getActionBarToolbar().removeView(logoImage); getActionBarToolbar().addView(logoImage, lp); 我得到:
我有类(class)评论一对多关系。在类(class)表中有 id 和 title 列。在 Review 表中,有 id、comment 和 course_id,其中“course_id”作为指向类(
我在 stackoverflow 上阅读了不同的答案,了解如何销毁 wigdet/jQueryObject 并取消绑定(bind)其上的所有事件。 这就是我的想法。 $('选择器').remove()
我有一个由一个线程填充的 byte[] 列表,然后我有另一个线程正在从该列表中读取并通过网络发送项目。 每次我读取线程 2 中的项目时,我都想将其从内存中清除。但是因为我正在使用线程,如果我使用 .r
就算法而言,从连续数组中删除一组元素可以分两部分有效地完成。 将所有不删除的元素移到数组的前面。 将数组标记得更小。 这可以在 C++ 中使用 erase-remove 习惯用法来完成。 vector
我尝试删除包含在 map 中渲染的制造商的 View 。当我单击按钮时,事件 click .ver 被激活,但没有任何反应,并且我收到以下错误:Uncaught TypeError: undefine
场景: 使用 jQuery 2.0.1 构建的应用程序。 您的团队更喜欢原生 JavaScript。 选项有jQuery .remove()和 ChildNode.remove() . 您需要删除节点
最初我有一个像这样的删除功能: function ViewWorkflowDetail(btn, workflowId) { $("#workflowDetailPanel").remov
我正在编写 C++ 代码来解决 Leetcode 中的这个问题:https://leetcode.com/problems/remove-element/ Given an array nums an
根据太阳, "Iterator.remove is the only safe way to modify a collection during iteration; the behavior is
众所周知,从 std::vector 中完全删除所需项的一种好方法是 erase-remove idiom . 如以上链接中所述(截至本文发布日期),在代码中,erase-remove 习惯用法如下所
我在 HashSet 上调用 Iterator.remove() 时遇到问题。 我有一组带有时间戳的对象。在将新项目添加到集合之前,我会遍历集合,识别该数据对象的旧版本并将其删除(在添加新对象之前)。
这段代码: Collection col = new ArrayList(); col.add("a"); col.add("b"); col.add("c");
我试图通过在下面输入来卸载 conda 环境基础, conda env remove -n base 正如我所建议的那样,我尝试通过使用来停用基地 conda deactivate base 我再次尝
我已经对我的 IOS 应用程序进行了质量扫描分析。我收到以下警告: The binary has Runpath Search Path (@rpath) set. In certain cases
这个问题已经有答案了: Properly removing an Integer from a List (8 个回答) 已关闭 4 年前。 我是java新手。看起来很简单,但我不明白为什么会发生这种
我是一名优秀的程序员,十分优秀!