Collections.newSetFromMap(»ConcurrentHashMap«)与Collections.synchronizedSet(»HashSet«)

时间:2012-07-05 18:54:43

标签: java collections concurrency thread-safety hashset

显然,有两种方法可以使用Java的HashSet API获取线程安全的Collections实例。

  • 他们有什么不同?
  • 哪种情况,在什么情况下优先于另一种?

5 个答案:

答案 0 :(得分:23)

你可能想到的是

Set<Type> set = Collections.newSetFromMap(new ConcurrentHashMap<Type, Boolean>());

这支持并发更新和读取。它的迭代器不会抛出ConcurrentModicationException。在哪里

Set<Type> set = Collections.synchronizedSet(new HashSet<Type());

重量更轻,但一次只允许一个线程访问该组。你需要明确地锁定集合,如果你想要迭代它,你仍然可以获得CME,如果你不以安全的方式更新它(当迭代它时)

答案 1 :(得分:6)

第一个返回一个Set,它基本上具有与作为参数传递的映射相同的线程安全性和性能保证。如果映射不是线程安全的,则该集合也不是。您通常使用此方法从并发映射创建并发集,因为API中没有ConcurrentHashSet。

第二个返回给定集合的代理,该集合的所有方法都已同步。

答案 2 :(得分:2)

实际上,您可能会获得多个Set线程安全实现。

予。 Collections.synchronizedSet(新的HashSet

我不推荐这个解决方案。它本身是线程安全的,在并发环境中仍然必须小心使用。参见:

Stack stack = new SynchronizedArrayStack(new ArrayStack());
...
// don't do this in a multi-threaded environment
if (!stack.isEmpty()) {
  stack.pop();              // can throw IllegalStateException
}

因此,您必须使用客户端锁定:

synchronized(stack) {
  if (!stack.isEmpty()) {
    stack.pop();
  }
}

II。 Set接口的第二个替代并发实现 - CopyOnWriteArraySet。但是,此解决方案不应在您期望进行许多搜索或插入的上下文中使用。但是,迭代每个元素的成本比HashSet要快O(1),并且它有一个在某些应用程序中非常引人注目的优点。

III。最后一个使用CuncurrentHashMap的实现:

Collections.newSetFromMap(new ConcurrentHashMap<Type, Boolean>());

它使用java.util.concurrent.locks.Lock的实现。映射将自身划分为可以单独锁定的部分,从而提高了并发性。所以你应该在最后两个选项中进行选择。

Thera也是排序集必须的选项。我建议你阅读Java Generics and Collections11.5 Collections and Thread Safety

答案 3 :(得分:1)

你错了。 newSetFromMap()不提供线程安全性。再次检查Javadoc。

这两种方法的输入类型也有不同之处。

答案 4 :(得分:1)

Collections API将地图构造留给客户端,如下所示:

ConcurrentHashMap<String, Boolean> conMap = new   ConcurrentHashMap<String, Boolean>();
Set<String> users = Collections.newSetFromMap(conMap);
System.out.println("Users: " + users);
users.add("Jon");//results in adding to the conMap instance
users.add("Tyron");
System.out.println("Users: " + users);
System.out.println("conMap = " + conMap);

添加到集合中也会添加到地图

用户:[Tyron,Jon] conMap = {Tyron = true,Jon = true}

conMap.put("Jubin", Boolean.FALSE);
System.out.println("Users: " + users);
System.out.println("conMap = " + conMap);

添加到地图也会导致添加到集

用户:[Tyron,Jubin,Jon] conMap = {Tyron = true,Jubin = false,Jon = true}

ConcurrentHashMap.newKeySet使用KeySetView

创建新的HashMap
ConcurrentHashMap.KeySetView<String, Boolean> keySetView = ConcurrentHashMap.newKeySet();
keySetView.add("Feba");
System.out.println("keySetView = " + keySetView);
System.out.println("keySetView.getMap() = " + keySetView.getMap());

keySetView = [Feba] keySetView.getMap()= {Feba = true}

keySetView.getMap().put("BeN",Boolean.TRUE);
System.out.println("keySetView = " + keySetView);
System.out.println("keySetView.getMap() = " + keySetView.getMap());

keySetView = [BeN,Feba] keySetView.getMap()= {BeN = true,Feba = true}