为什么要同步SynchronizedMap或SynchronizedCollections? [英] Why to synchronize on SynchronizedMap or SynchronizedCollections?

查看:106
本文介绍了为什么要同步SynchronizedMap或SynchronizedCollections?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我指的是此处并使用作者代码示例的问题,现在我的问题是

I am referring to question asked here and using authors code example, now my question is


  1. 为什么作者使用 synchronized(synchronizedMap),是否真的有必要因为synchronizedMap总能确保那里是没有两个线程试图读取/放置操作地图所以为什么我们需要在地图上同步

  1. Why does author uses synchronized(synchronizedMap), is it really necessary because synchronizedMap will always make sure that there are no two threads trying to do read/put operation on Map so why do we need to synchronize on that map itself?

真的很感激解释。

  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);
      }
    }
  }
}


推荐答案


为什么我们需要同步 synchronizemap 本身?

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

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 conditions in the code that is calling the 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.

如果查看链接的代码,他们首先检查密钥是否存在,然后如果密钥确实存在,则将值放入映射中不存在。您需要防止2个线程检查密钥的存在,然后将两个放入映射中。比赛将首先放在哪一个,哪一个将覆盖之前的放置。

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 both of them putting into the map. The race is which one will put first and which one will overwrite the previous put.

同步集合保护自己免受破坏地图本身的多个线程的影响。它确实防止多次调用地图的逻辑竞争条件。

The synchronized collection protects itself from multiple threads corrupting the map itself. It does not protect 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);
   }
}

这是<$ c的原因之一$ c> ConcurrentMap 接口有 putIfAbsent(K键,V值); 。这样做需要两个操作,所以你可能不需要围绕它进行同步。

This is one of the reasons why the ConcurrentMap interface has the putIfAbsent(K key, V value);. That does not require two operations so you may not need to synchronize around it.

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

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);
}

最后,如果地图上的大部分操作都需要在 synchronized 阻止无论如何,您可能不会为<$​​ c $ c> synchronizedMap 付费,只需使用 HashMap 总是在 synchronized 块内。

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.

这篇关于为什么要同步SynchronizedMap或SynchronizedCollections?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆