只需使用一些源代码完善答案。
http://www.docjar.com/html/api/java/util/Collections.java.html
1)是的,它是一个集合包装器(私有静态类的一个实例SynchronizedSet
),如类代码中所示line 2054
。Collections
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 上进行同步,因为返回的 Set(SynchronizedSet) 中的所有操作Set s = m.keySet();
都在同一个互斥锁(返回的同步映射)上同步,而不是在返回的集合上同步。这可以从以下几点看出:
a) 返回的 Map (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)当我们通过 map 迭代时,Iterator i = s.iterator();
我们应该在 m 而不是 s 上同步它,因为返回的 Set(SynchronizedSet) inSet s = m.keySet();
中的操作在同一个互斥锁(返回的同步映射)上同步,而不是在 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 }