java Collections.newSetFromMap(?ConcurrentHashMap?) 与 Collections.synchronizedSet(?HashSet?)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11350723/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 04:44:44  来源:igfitidea点击:

Collections.newSetFromMap(?ConcurrentHashMap?) vs. Collections.synchronizedSet(?HashSet?)

javacollectionsconcurrencythread-safetyhashset

提问by fbahr

Apparently, there are two ways to obtain a thread-safe HashSetinstance using Java's CollectionsAPI.

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

  • How do they differ?
  • Which, and under what circumstances, is to be preferred over the other?
  • 它们有何不同?
  • 在什么情况下,哪个优先于另一个?

回答by Peter Lawrey

What you may be thinking of is

你可能会想到的是

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

This supports concurrent updates and reads. Its Iterator won't throw ConcurrentModicationException. where as

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

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

Is more light weight but only allows one thread at a time to access the set. You need to lock the set explicitly if you want to Iterator over it and you can still get a CME if you don't update it in a safe way (while iterating over it)

重量更轻,但一次只允许一个线程访问该集合。如果您想对其进行迭代器,则需要明确锁定该集合,并且如果您不以安全的方式更新它(在迭代它时),您仍然可以获得 CME

回答by JB Nizet

The first one returns a Set that basically has the same thread-safe and performance guarantees as the map passed as argument. If the map isn't thread-safe, the set won't be either. You typically use this method to create a concurrent set from a concurrent map, because there is no ConcurrentHashSet in the API.

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

The second one returns a proxy to the given set, which has all its methods synchronized.

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

回答by Alexandr

Actually you may get several Set thread-safe implementations.

实际上你可能会得到几个 Set 线程安全的实现。

I. Collections.synchronizedSet(new HashSet

一、Collections.synchronizedSet(new HashSet

I would not recommend this solution. It is itself thread-safe, must still be used with care in a concurrent environment. See:

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

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

As a result you must use client-side locking:

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

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

II. The second alternative concurrent implementation of Set interface - CopyOnWriteArraySet. However this solution should not be used in a context where you were expecting many searches or insertions. But iteration costs O(1) per element faster than HashSet and it has one advantage which is really compelling in some applications.

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

III. The last one uses the implementation of CuncurrentHashMap:

三、最后一个使用了 CuncurrentHashMap 的实现:

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

It uses implementations of java.util.concurrent.locks.Lock. The map divides itself into parts that can be separately locked, giving improved concurrency. So you should choose between the last two options.

它使用 java.util.concurrent.locks.Lock 的实现。地图将自身分成可以单独锁定的部分,从而提高了并发性。因此,您应该在最后两个选项之间进行选择。

Thera are also options for sorted set impelementations. I would recommend you to read Java Generics and Collectionschapter 11.5 Collections and Thread Safety.

Thera 也是排序集实现的选项。我建议你阅读Java Generics and Collections章节11.5 Collections and Thread Safety

回答by jtkSource

The Collections API leave the construction of the map to the client as below:

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);

Adding to the set also adds to the map

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

Users: [Tyron, Jon] conMap = {Tyron=true, Jon=true}

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

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

Adding to the Map also results on adding to the Set

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

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

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

ConcurrentHashMap.newKeySet creates new HashMap with the KeySetView

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 = [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}

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

回答by user207421

You are mistaken. newSetFromMap() does not provide thread safety. Check the Javadoc again.

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

There is also the small matter that the input types of these two methods are different.

还有一个小问题就是这两种方法的输入类型不同。