为什么要同步SynchronizedMap或SynchronizedCollections?
我指的是这里提出的问题并使用作者代码示例,现在我的问题是
- 为什么作者使用
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执行第二部分的情况,你的业务操作可能会导致奇怪的结果(即使地图的更新是同步的)