【发布时间】:2021-04-27 02:30:21
【问题描述】:
假设我有一个名为 map 的共享 ConcurrentHashMap
第一个线程执行这段代码:
map.put("One", 2);
第二个线程执行这段代码:
synchronized (map) {
Integer number = map.get("One");
System.out.println(number == map.get("One"));
}
由于 ConcurrentHashMap 使用锁定条带方法而不是锁定整个对象,我不认为所描述的场景是线程安全的。
特别是我不知道Integer number = map.get("One"); 调用和第二个线程中的System.out.println(number == map.get("One")); 调用之间的第一个线程中是否可能存在map.put("One", 2); 交错,尽管两者都在同步块内。
那么该代码是否有可能打印错误?
【问题讨论】:
-
您的理解是正确的,代码可能打印错误。没有什么能阻止线程在这里交错。但是,这并不意味着
put()本身不是线程安全的(基于您问题的标题)。 -
@PanagiotisBougioukos 这个问题的重点是
get被连续调用两次,以及如何防止导致两个不同的结果。同步对于防止这种情况是必要的,但提供的代码中的同步不会这样做,因为它没有使用与put方法相同的锁进行同步。 -
更一般地,您可能会问,“线程安全的类可以以非线程安全的方式使用吗?”答案是响亮的“是的!”完全使用线程安全组件构建程序并不能自动保证您的程序是线程安全的。
-
继@SolomonSlow 的评论之后:密切关注“线程安全”的含义很重要:从内部状态的角度来看,CHM 是线程安全的;但是您使用该 CHM 的代码可能有其自己的、单独的不变量,它们具有单独的线程安全要求。在这种情况下,您的代码需要确保在多个线程访问时正确保留不变量。
-
请注意,
ConcurrentHashMap在 Java 7 及更早版本中使用了锁分条。从 Java 8 开始,它不使用锁条带化。但即使在那些旧版本中,一个普通的get调用在理想情况下也不会锁定任何东西。
标签: java multithreading concurrency synchronization concurrenthashmap