java - HashMap 对于不同的键是线程安全的吗?

标签 java multithreading thread-safety hashmap

如果我有两个多个线程访问一个 HashMap,但保证它们永远不会同时访问同一个键,那还会导致竞争条件吗?

最佳答案

在@dotsid 的回答中,他这样说:

If you change a HashMap in any way then your code is simply broken.

他是对的。如果线程使用不相交的键集,则在没有同步的情况下更新的 HashMap 将破坏 even。以下是只是一些1可能出错的地方。

  • 如果一个线程执行 put,那么另一个线程可能会看到 HashMap 大小的陈旧值。

  • 如果一个线程使用与第二个线程的键(当前)在同一个哈希桶中的键执行 put,则第二个线程的映射条目可能会暂时或永久丢失。这取决于哈希链(或其他)是如何实现的。

  • 当一个线程执行 put 触发表的重建时,另一个线程可能会看到哈希表数组引用、其大小、其内容或哈希链的临时或陈旧版本.可能会出现困惑。

  • 当一个线程执行 put 的键与其他线程使用的某个键发生冲突,而后一​​个线程对其键执行 put ,那么后者可能会看到哈希链引用的陈旧副本。可能会出现困惑。

  • 当一个线程使用与其他线程的键之一冲突的键来探测表时,它可能会在链上遇到该键。它将在该键上调用 equals,如果线程未同步,则 equals 方法可能会在该键中遇到陈旧状态。

如果您有两个线程同时执行 putremove 请求,则会出现许多竞争条件。

我能想到三个解决方案:

  1. 使用 ConcurrentHashMap
  2. 使用常规的 HashMap 但在外部同步;例如使用原始互斥锁、Lock 对象等。但请注意,这可能会因锁争用而导致并发瓶颈。
  3. 为每个线程使用不同的 HashMap。如果线程确实有一组不相交的键,那么(从算法的角度来看)它们应该不需要共享一个 Map。实际上,如果您的算法涉及线程在某个时刻迭代映射的键、值或条目,则将单个映射拆分为多个映射可以显着加快该部分的处理速度。

1 - 我们无法列举所有可能出错的事情。首先,我们无法预测所有 JVM 将如何在所有平台上处理 JMM 的 unspecified 方面。但是无论如何,您都不应该依赖此类信息。你需要知道的是,像这样使用 HashMap 是根本错误的。执行此操作的应用程序已损坏......即使您尚未观察到损坏的症状。

关于java - HashMap 对于不同的键是线程安全的吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2688629/

相关文章:

java - 大米之谜 - 为什么 "If else"语句不能正确循环?

java - 为什么这个 for 循环会被跳过?

java - 发生在 Java 内存模型之前和程序顺序

c# - 实现 C# 通用超时

python - 当 QThread() 停止运行时(Python),我是否需要手动调用 .quit() 方法?

java - 两个按钮和它们之间的 webView

java - Future cancel 触发的 ListenableFuture 回调

python - 文件 I/O 操作会释放 Python 中的 GIL 吗?

multithreading - Postgres 9.3 中 SELECT FOR UPDATE 的并发问题

Java:是 CountDownLatch 线程安全的