[英]Collections.synchronizedMap
來自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()返回的Set也是一個集合包裝器還是一個不同步的集合?
編輯:
2)是否需要在m in上同步
synchronized(m) { // Synchronizing on m, not s!
我們不能在s而不是m上同步嗎?
1:是的,它返回一個與Map共享互斥鎖的同步集。
2:是的,您需要在迭代時手動保持鎖定。 如果你沒有在對next()的調用之間進行更改,那么你仍然會遇到問題。 請記住,它是HashMap規范的一部分,如果另一個線程,例如m.put("foo", "bar");
在你對i.next()
兩次調用之間,然后next()
將拋出ConcurrentModificationException。 為了防止這種情況,你可以鎖定整個地圖,這樣在你完成迭代器之前,沒有人可以改變它。 僅鎖定該集合不會阻止任何人添加到地圖中。
如果您需要在可能發生並發訪問時進行迭代,那么您應該查看ConcurrentMap的實現,以使您的生活更輕松。
1)返回的集是一個SynchronizedSet
,它使用相同的互斥鎖來鎖定。
2) 映射本身不會同步,而是單獨的互斥對象,因此在映射上進行同步不會阻止其他有權訪問映射的線程進行修改。 只有在修改了地圖的所有代碼也在地圖上同步時,這才有效。 地圖會自行同步,但奇怪的是使用單獨的mutex
變量引用自身。 因此,在地圖上進行同步將阻止通過同步包裝器對地圖進行其他修改。 請注意,在keySet()
方法返回的同步集中使用相同的互斥鎖。
編輯:之前錯了。
SynchronizedSet
在SynchronizedMap實例本身同步。 請記住 - Set s只是原始地圖支持的視圖。 所以我們要確保地圖不會改變。
查看代碼是有益的。 Line 1999有SynchronizedMap的聲明。
只是用一些源代碼改進答案。
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使用與Collections.synchronizedMap(new HashMap());
返回的SynchronizedMap相同的互斥鎖Collections.synchronizedMap(new HashMap());
正在使用。
2)有必要在m而不是s上同步它,因為在Set s = m.keySet();
中返回Set(SynchronizedSet)中的所有操作Set s = m.keySet();
在同一個互斥鎖(返回的同步映射)上同步,但在返回的集合上不同步。 這可以從以下幾點看出:
a) Collections.synchronizedMap(new HashMap());
返回的Map(SynchronizedMap)中的所有操作Collections.synchronizedMap(new HashMap());
在返回的地圖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();
迭代地圖Iterator i = s.iterator();
我們應該在m而不是s上同步它,因為在Set s = m.keySet();
中返回Set(SynchronizedSet)中的操作Set 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 }
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.