同步Set线程的构造函数是否安全?

获取java.util.Set的同步版本的最简单方法是使用Collections.synchronizedSet(),如下所示:

Set mySyncSet = Collections.synchronizedSet(new HashSet()); 

Java API说明了这个新对象:

当迭代它时,用户必须手动同步返回的集合

我的问题是,如果我使用这样的复制构造函数创建此Set的副本:

 Set mySetCopy = new HashMap(mySyncSet); 

它是线程安全的吗? (不是HashMap构造函数使用迭代来获取Set的成员吗?)或者我应该手动同步这样的操作?:

 Set mySetCopy; synchronized(mySyncSet) { mySetCopy = new HashMap(mySyncSet); } 

让我们来看看代码:

 public HashSet(Collection c) { map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16)); addAll(c); } 

所以只需调用addAll

 public boolean addAll(Collection c) { boolean modified = false; for (E e : c) if (add(e)) modified = true; return modified; } 

所以这会循环你给它的Collection

答案是否定的,构造函数副本不是线程安全的。

在将其传递给构造函数之前,您需要使用第二个选项并对Set执行显式synchronized

第二种方式更可取。 如果某个线程修改了你的原始线程,当这个线程迭代你的集合以复制对你的新集合的引用时,你将遇到麻烦。

访问或修改集合的所有代码都应该在JavaDoc指定的同一实例上手动同步。