简体   繁体   中英

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

Apparently, there are two ways to obtain a thread-safe HashSet instance using Java's Collections utility class.

I ask:

  • How do they differ?
  • Which, and under what circumstances, is to be preferred over the other?

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

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)

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.

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

Actually you may get several Set thread-safe implementations.

I. 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.

III. The last one uses the implementation of 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.

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

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

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}

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}

ConcurrentHashMap.newKeySet creates new HashMap with the KeySetView

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}

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM