来自javadocs
Map m = Collections.synchronizedMap(new HashMap());
...
Set s = m.keySet(); // Needn't be in synchronized block
...
synchronized(m) { // Synchronizing on m, not s!
Iterator i = s.iterator(); // Must be in synchronized block
while (i.hasNext())
foo(i.next());
}两个问题:
1)是由m.keySet()返回的,还是一个集合包装器,还是只是一个不同步的集合?
编辑:
(2)是否有必要在m上同步
synchronized(m) { // Synchronizing on m, not s!我们不能用s而不是m来同步吗?
发布于 2012-05-19 06:28:37
1:是的,它返回与Map共享互斥对象的同步集。
是的,你需要在迭代时手动保持锁。如果不进行更改,则可以在调用next()之间进行更改,但仍然会遇到问题。请记住,如果另一个线程(例如,在对HashMap的两个调用之间执行m.put("foo", "bar"); ),则next()将抛出ConcurrentModificationException,这是i.next()规范的一部分。为了防止这种情况,您可以锁定整个映射,以便在您完成迭代器之前,没有人可以更改它。锁定设置不会阻止任何人添加到地图上。
如果您需要在并发访问发生时进行迭代,则应该查看ConcurrentMap的实现,以使您的生活更加轻松。
发布于 2012-05-19 06:31:24
编辑:以前是错的。
SynchronizedSet实例本身上同步的一个SynchronizedMap。记住-集合s只是一个由原始地图支持的视图。所以我们要确保地图不会变。
看看代码是很有教育意义的。第1999行有SynchronizedMap的声明。
发布于 2012-06-14 08:00:54
只是用一些源代码改进了答案。
http://www.docjar.com/html/api/java/util/Collections.java.html
1)是的,它是集合包装器(私有静态类SynchronizedSet的实例),如来自Collections类代码的line 2054中所示。
2051 public Set<K> keySet() {
2052 synchronized (mutex) {
2053 if (keySet==null)
2054 keySet = new SynchronizedSet<>(m.keySet(), mutex);
2055 return keySet;
2056 }
2057 }请注意,此SynchronizedSet使用的互斥对象与SynchronizedMap返回的Collections.synchronizedMap(new HashMap());使用的互斥对象相同。
2)必须在m而不是s上同步它,因为在返回集(SynchronizedSet)中的所有操作都是在同一个互斥(返回的同步映射)上同步的,而不是在返回的集合上同步的。从以下几点可以看出这一点:
A)由SynchronizedMap返回的地图( Collections.synchronizedMap(new HashMap()); )中的所有操作都同步在返回的Map iteslf上作为互斥项,从2004、2010、2035行的代码行中可以看出这一点。:
1992 public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m) {
1993 return new SynchronizedMap<>(m);
1994 }SynchronizedMap类定义为:
1999 private static class SynchronizedMap<K,V>
2000 implements Map<K,V>, Serializable {
2001 ...
2002
2003 private final Map<K,V> m; // Backing Map
2004 final Object mutex; // Object on which to synchronize
...
SynchronizedMap(Map<K,V> m) {
2007 if (m==null)
2008 throw new NullPointerException();
2009 this.m= m;
2010 mutex = this;
2011 }
...
2034 public V put(K key, V value) {
2035 synchronized (mutex) {return m.put(key, value);}
2036 }
...
}B)当我们通过Iterator i = s.iterator();迭代映射时,我们应该在m而不是s上同步它,因为Set s = m.keySet();中返回集(SynchronizedSet)中的操作是在同一个互斥体(返回的同步映射)上同步的,而不是在s上同步的,如第2054行所示。
2051 public Set<K> keySet() {
2052 synchronized (mutex) {
2053 if (keySet==null)
2054 keySet = new SynchronizedSet<>(m.keySet(), mutex);
2055 return keySet;
2056 }
2057 }https://stackoverflow.com/questions/10662835
复制相似问题