是否设置了以下代码来正确同步synchronizedMap
上的调用
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);
}
}
}
}
据我所知,我需要addToMap()
中的synchronized块来防止另一个线程在我完成对put()
的调用之前调用remove()
或containsKey()
,但我不需要doWork()
中的synchronized块,因为在remove()
返回之前,另一个线程不能进入remove()
中的synchronized块,因为我最初是用Collections.synchronizedMap()
创建映射的。对吗?有没有更好的方法来做这件事?
发布于 2009-02-19 20:53:46
Collections.synchronizedMap()
保证您希望在映射上运行的每个原子操作都是同步的。
但是,在map上运行两个(或更多)操作必须在一个块中同步。所以,是的,你的同步是正确的。
发布于 2009-02-19 20:52:37
如果您使用的是JDK6,那么您可能需要查看ConcurrentHashMap
注意该类中的putIfAbsent方法。
发布于 2015-09-16 20:29:23
是的,您的同步是正确的。我将更详细地解释这一点。只有在必须依赖于synchronizedMap对象的方法调用序列中的后续方法调用的前一个方法调用的结果的情况下,才必须同步对synchronizedMap对象的两个或多个方法调用。让我们来看看这段代码:
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);
}
}
在这段代码中
synchronizedMap.get(key).add(value);
和
synchronizedMap.put(key, valuesList);
方法调用依赖于上一个
synchronizedMap.containsKey(key)
方法调用。
如果方法调用的序列没有同步,结果可能是错误的。例如,thread 1
正在执行方法addToMap()
,而thread 2
正在执行方法doWork()
,synchronizedMap
对象上的方法调用序列可能如下所示:Thread 1
已执行该方法
synchronizedMap.containsKey(key)
结果是"true
“。在该操作系统将执行控制权切换到thread 2
并执行之后
synchronizedMap.remove(key)
在该执行控制被切换回thread 1
并且它已经被执行之后,例如
synchronizedMap.get(key).add(value);
如果认为synchronizedMap
对象包含key
,则将抛出NullPointerException
,因为synchronizedMap.get(key)
将返回null
。如果synchronizedMap
对象上的方法调用序列不依赖于彼此的结果,那么您就不需要同步该序列。例如,您不需要同步此序列:
synchronizedMap.put(key1, valuesList1);
synchronizedMap.put(key2, valuesList2);
这里
synchronizedMap.put(key2, valuesList2);
方法调用不依赖于上一个
synchronizedMap.put(key1, valuesList1);
方法调用(它不关心是否有线程在两个方法调用之间进行了干预,例如是否删除了key1
)。
https://stackoverflow.com/questions/567068
复制相似问题