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?
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With