Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are final unmodifiable sets thread safe?

The javadocs are not clear about this: are unmodifiable sets thread safe? Or should I worry about internal state concurrency problems?

Set<String> originalSet = new HashSet<>();
originalSet.add("Will");
originalSet.add("this");
originalSet.add("be");
originalSet.add("thread");
originalSet.add("safe?");
final Set<String> unmodifiableSet = Collections.unmodifiableSet(originalSet);
originalSet = null; // no other references to the originalSet

// Can unmodifiableSet be shared among several threads?  

I have stumbled upon a piece of code with a static, read-only Set being shared against multiple threads... The original author wrote something like this:

mySet = Collections.synchronizedSet(Collections.unmodifiableSet(originalSet));

And then every thread access it with code such as:

synchronized (mySet) {
  // Iterate and read operations
}

By this logic only one thread can operate on the Set at once... So my question is, for a unmodifiable set, when using operations such as for each, contains, size, etc, do I really need to synchronize access?

like image 615
Anthony Accioly Avatar asked Nov 18 '13 03:11

Anthony Accioly


2 Answers

If it's an unmodifiable Set<String>, as per your example, then you're fine; because String objects are immutable. But if it's a set of something that's not immutable, you have to be careful about two threads both trying to change the same object inside the set.

You also have to be careful about whether there's a reference somewhere to the Set, that's not unmodifiable. It's possible for a variable to be unmodifiable, but still be referring to a Set which can be modified via a different variable; but your example seems to have that covered.

like image 91
Dawood ibn Kareem Avatar answered Nov 19 '22 04:11

Dawood ibn Kareem


Objects that are "de facto" immutable are thread safe. i.e. objects that never change their state. That includes objects that could theoretically change but never do. However all the objects contained inside must also be "de facto" immutable. Furthermore the object only starts to become thread safe when you stop modifying it. And it needs to be passed to the other threads in a safe manner. There are 2 ways to do that.

1.) you start the other threads only after you stopped modifying your object. In that case you don't need any synchronization at all.

2.) the other threads are already running while you are modifying the object, but once you completed constructing the object, you pass it to them through a synchronized mechanism e.g. a ConcurrentLinkedDeque. After that you don't need any further synchronization.

like image 21
SpiderPig Avatar answered Nov 19 '22 06:11

SpiderPig