首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Collections.synchronizedMap

Collections.synchronizedMap
EN

Stack Overflow用户
提问于 2012-05-19 06:18:48
回答 3查看 2.8K关注 0票数 4

来自javadocs

代码语言:javascript
复制
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上同步

代码语言:javascript
复制
 synchronized(m) {  // Synchronizing on m, not s!

我们不能用s而不是m来同步吗?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-05-19 06:28:37

1:是的,它返回与Map共享互斥对象的同步集。

是的,你需要在迭代时手动保持锁。如果不进行更改,则可以在调用next()之间进行更改,但仍然会遇到问题。请记住,如果另一个线程(例如,在对HashMap的两个调用之间执行m.put("foo", "bar"); ),则next()将抛出ConcurrentModificationException,这是i.next()规范的一部分。为了防止这种情况,您可以锁定整个映射,以便在您完成迭代器之前,没有人可以更改它。锁定设置不会阻止任何人添加到地图上。

如果您需要在并发访问发生时进行迭代,则应该查看ConcurrentMap的实现,以使您的生活更加轻松。

票数 5
EN

Stack Overflow用户

发布于 2012-05-19 06:31:24

编辑:以前是错的。

  1. 它是在SynchronizedSet实例本身上同步的一个SynchronizedMap。
  2. 有必要在m上同步,以确保当您处于循环中时,映射不会从您的下面改变。

记住-集合s只是一个由原始地图支持的视图。所以我们要确保地图不会变。

看看代码是很有教育意义的。第1999行有SynchronizedMap的声明。

票数 1
EN

Stack Overflow用户

发布于 2012-06-14 08:00:54

只是用一些源代码改进了答案。

http://www.docjar.com/html/api/java/util/Collections.java.html

1)是的,它是集合包装器(私有静态类SynchronizedSet的实例),如来自Collections类代码的line 2054中所示。

代码语言:javascript
复制
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行的代码行中可以看出这一点。:

代码语言:javascript
复制
1992       public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m) {
 1993           return new SynchronizedMap<>(m);
 1994       }

SynchronizedMap类定义为:

代码语言:javascript
复制
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行所示。

代码语言:javascript
复制
2051        public Set<K> keySet() {
 2052               synchronized (mutex) {
 2053                   if (keySet==null)
 2054                       keySet = new SynchronizedSet<>(m.keySet(), mutex);
 2055                   return keySet;
 2056               }
 2057           }
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/10662835

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档