为什么要同步SynchronizedMap或SynchronizedCollections?

Rac*_*hel 14 java multithreading

我指的是这里提出的问题并使用作者代码示例,现在我的问题是

  1. 为什么作者使用synchronized(synchronizedMap),是否真的有必要,因为synchronizedMap将始终确保没有两个线程尝试进行read/put操作,Map为什么我们需要synchronize在该地图本身?

真的很感激解释.


  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);
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

Gra*_*ray 18

为什么我们需要同步synchronizemap呢?

您可能需要在已经同步的集合上进行同步,因为您正在对集合执行两个操作 - 在您的示例中,a containsKey(),然后是a put().您正试图在调用集合的代码中防止竞争条件.此外,在这种情况下,块还保护值,以便多个线程可以将它们的值添加到这些未同步的集合中.synchronizedArrayList

如果查看链接的代码,他们首先检查密钥是否存在,然后在密钥不存在时将值放入映射中.您需要防止2个线程的一个重要的生存确认,然后两个人投入的地图.比赛是哪一个将首先放在哪一个,哪一个将覆盖之前的看跌期权.

同步集合可以防止多个线程破坏映射本身.它不能防止多次调用地图时的逻辑竞争条件.

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);
   }
}
Run Code Online (Sandbox Code Playgroud)

这是ConcurrentMap界面具有的原因之一putIfAbsent(K key, V value);.但这并不需要两个操作,所以你可能并不需要围绕它进行同步.

顺便说一句,我会重写上面的代码:

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);
}
Run Code Online (Sandbox Code Playgroud)

最后,如果地图上的大多数操作synchronized无论如何都需要在一个块中,你也可以不用付钱synchronizedMap而只是使用一个HashMap总是在synchronized块里面.

  • 我认为上面的例子是完美的@Rachel.如果没有`synchronized`包装器,两个线程可以使用相同的`key`同时执行`containsKey`行.他们都测试密钥的存在,他们都看到密钥不在地图中.两个线程都创建一个新列表并将其值添加到每个列表中.第一个线程用它的列表执行put,第二个线程用它的列表执行put,_overwriting_第一个线程的put.这就是竞争条件.请看这里:http://en.wikipedia.org/wiki/Race_conditions#Computing (4认同)
  • @Rachel他刚才解释说不是吗? (2认同)
  • 正如我在@Rachel的回答中所说,`synchronizedMap`可以防止_internal_ race条件,这会破坏地图数据本身.它无法防止您发布的示例,我注释了调用多个方法的位置. (2认同)