为什么要同步SynchronizedMap或SynchronizedCollections?

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

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

真的很感激解释。


  public class MyClass { private static Map<String, List> synchronizedMap = Collections.synchronizedMap(new HashMap<String, List>()); public void doWork(String key) { List 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 valuesList = new ArrayList(); valuesList.add(value); synchronizedMap.put(key, valuesList); } } } } 

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

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

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

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

 synchronized (synchronizedMap) { // test for a key in the map if (synchronizedMap.containsKey(key)) { synchronizedMap.get(key).add(value); } else { List valuesList = new ArrayList(); valuesList.add(value); // store a value into the map synchronizedMap.put(key, valuesList); } } 

这是ConcurrentMap接口具有putIfAbsent(K key, V value);的原因之一putIfAbsent(K key, V value); 。 这不需要两个操作,因此您可能不需要围绕它进行同步。

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

 synchronized (synchronizedMap) { // test for a key in the map List valuesList = synchronizedMap.get(key); if (valueList == null) { valuesList = new ArrayList(); // store a value into the map synchronizedMap.put(key, valuesList); } valuesList.add(value); } 

最后,如果地图上的大多数操作无论如何都需要在synchronized块中,您也可以不为synchronizedMap付费,只需在synchronized块内部使用HashMap

它不仅仅是关于更新synchronizedMap值,而是关于影响地图的操作序列。 在同一方法内的地图上发生了两个操作。

如果你没有同步块/方法,假设可能有类似Thread1执行第一部分和thread2执行第二部分的情况,你的业务操作可能会导致奇怪的结果(即使地图的更新是同步的)