簡體   English   中英

Collections.synchronizedMap

[英]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()方法返回的同步集中使用相同的互斥鎖。

編輯:之前錯了。

  1. 這是一個SynchronizedSet在SynchronizedMap實例本身同步。
  2. 有必要在m上進行同步,以確保在循環中地圖不會從你下面改變。

請記住 - 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM