java 为什么要在 SynchronizedMap 或 SynchronizedCollections 上进行同步?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11671801/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why to synchronize on SynchronizedMap or SynchronizedCollections?
提问by Rachel
I am referring to question asked hereand using authors code example, now my question is
我指的是这里提出的问题并使用作者代码示例,现在我的问题是
- Why does author uses
synchronized(synchronizedMap)
, is it really necessary because synchronizedMap will always make sure that there are no two threads trying to doread/put
operation onMap
so why do we need tosynchronize
on that map itself?
- 为什么作者使用
synchronized(synchronizedMap)
,是否真的有必要,因为 synchronizedMap 将始终确保没有两个线程试图对其进行read/put
操作,Map
那么为什么我们需要synchronize
在该映射本身上进行操作?
Would really appreciate an explanation.
真的很感激解释。
public class MyClass {
private static Map<String, List<String>> synchronizedMap =
Collections.synchronizedMap(new HashMap<String, List<String>>());
public void doWork(String key) {
List<String> values = null;
while ((values = synchronizedMap.remove(key)) != null) {
//do something with values
}
}
public static void addToMap(String key, String value) {
synchronized (synchronizedMap) {
if (synchronizedMap.containsKey(key)) {
synchronizedMap.get(key).add(value);
}
else {
List<String> valuesList = new ArrayList<String>();
valuesList.add(value);
synchronizedMap.put(key, valuesList);
}
}
}
}
回答by Gray
why do we need to synchronize on that
synchronizemap
itself?
为什么我们需要同步它
synchronizemap
本身?
You may need to synchronize on an already synchronized collection because you are performing two operations on the collection -- in your example, a containsKey()
and then a put()
. You are trying to protect against race conditionsin the code that is callingthe collection. In addition, in this case, the synchronized
block also protects the ArrayList
values so that multiple threads can add their values to these unsynchronized collections.
您可能需要在已经同步的集合上进行同步,因为您正在对集合执行两个操作——在您的示例中, acontainsKey()
和 a put()
。您正在尝试防止调用集合的代码中出现竞争条件。此外,在这种情况下,块还保护这些值,以便多个线程可以将它们的值添加到这些未同步的集合中。synchronized
ArrayList
If you look at the code you linked to, they first check for the existence of the key and then put a value into the map if the key did not exist. You need to protect against 2 threads checking for a key's existence and then bothof them putting into the map. The race is which one will put first and which one will overwrite the previous put.
如果您查看链接到的代码,它们会首先检查键是否存在,如果键不存在,则将值放入映射中。您需要防止2个线程的一个重要的生存确认,然后两个人投入的地图。比赛是哪个先放,哪个覆盖前一个放。
The synchronized collection protects itself from multiple threads corrupting the map itself. It does notprotect against logic race conditions around multiple calls to the map.
同步集合保护自己免受破坏地图本身的多个线程的影响。它不能防止围绕对映射的多次调用的逻辑竞争条件。
synchronized (synchronizedMap) {
// test for a key in the map
if (synchronizedMap.containsKey(key)) {
synchronizedMap.get(key).add(value);
} else {
List<String> valuesList = new ArrayList<String>();
valuesList.add(value);
// store a value into the map
synchronizedMap.put(key, valuesList);
}
}
This is one of the reasons why the ConcurrentMap
interface has the putIfAbsent(K key, V value);
. That does notrequire two operations so you may not need to synchronize around it.
这是ConcurrentMap
界面具有putIfAbsent(K key, V value);
. 但这并不需要两个操作,所以你可能并不需要围绕它同步。
Btw, I would rewrite the above code to be:
顺便说一句,我将上面的代码重写为:
synchronized (synchronizedMap) {
// test for a key in the map
List<String> valuesList = synchronizedMap.get(key);
if (valueList == null) {
valuesList = new ArrayList<String>();
// store a value into the map
synchronizedMap.put(key, valuesList);
}
valuesList.add(value);
}
Lastly, if most of the operations on the map need to be in a synchronized
block anyway, you might as well not pay for the synchronizedMap
and just use a HashMap
always inside of synchronized
blocks.
最后,如果地图上的大多数操作synchronized
无论如何都需要在一个块中,那么您最好不要支付费用synchronizedMap
而只使用HashMap
始终在synchronized
块内。
回答by kosa
It is not just about updating synchronizedMap values, it is about sequence of operations effecting the map. There are two operations happening on the map inside same method.
这不仅仅是关于更新 synchronizedMap 值,而是关于影响地图的操作序列。在同一个方法中的地图上发生了两个操作。
If you don't synchronize block/method, assume there may be case like Thread1 executing first part and thread2 executing second part, your business operation may results in weird results (even though updates to map are synchronized)
如果你不同步block/method,假设可能会出现Thread1执行第一部分,thread2执行第二部分的情况,你的业务操作可能会导致奇怪的结果(即使对map的更新是同步的)