首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >Java同步块与Collections.synchronizedMap

Java同步块与Collections.synchronizedMap
EN

Stack Overflow用户
提问于 2009-02-19 20:44:09
回答 5查看 110.9K关注 0票数 87

是否设置了以下代码来正确同步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()创建映射的。对吗?有没有更好的方法来做这件事?

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2009-02-19 20:53:46

Collections.synchronizedMap()保证您希望在映射上运行的每个原子操作都是同步的。

但是,在map上运行两个(或更多)操作必须在一个块中同步。所以,是的,你的同步是正确的。

票数 91
EN

Stack Overflow用户

发布于 2009-02-19 20:52:37

如果您使用的是JDK6,那么您可能需要查看ConcurrentHashMap

注意该类中的putIfAbsent方法。

票数 15
EN

Stack Overflow用户

发布于 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)。

票数 11
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/567068

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档