Mike Q
Mike Q

Reputation: 23229

Do I have to use a thread-safe Map implementation when only reading from it?

If I do the following.

As I understand it the Map has been "safely published" because the other threads were started after the Map was fully populated so I think it is ok to access the Map from multiple threads as it cannot be modified after this point.

Is this right?

Upvotes: 9

Views: 2879

Answers (5)

Jed Wesley-Smith
Jed Wesley-Smith

Reputation: 4706

In short, no you don't need the map to be thread-safe if the reads are non-destructive and the map reference is safely published to the client.

In the example there are two important happens-before relationships established here. The final-field publication (if and only if the population is done inside the constructor and the reference doesn't leak outside the constructor) and the calls to start the threads.

Anything that modifies the map after these calls wrt the client reading from the map is not safely published.

We have for example a CopyOnWriteMap that has a non-threadsafe map underlying that is copied on each write. This is as fast as possible in situations where there are many more reads than writes (caching configuration data is a good example).

That said, if the intention really is to not change the map, setting an immutable version of the map into the field is always the best way to go as it guarantees the client will see the correct thing.

Lastly, there are some Map implementations that have destructive reads such as a LinkedHashMap with access ordering, or a WeakHashMap where entries can disappear. These types of maps must be accessed serially.

Upvotes: 2

卢声远 Shengyuan Lu
卢声远 Shengyuan Lu

Reputation: 32014

Immutable map is born to thread-safe. You could use ImmutableMap of Guava.

Upvotes: 1

aioobe
aioobe

Reputation: 421060

As I understand it the Map has been "safely published" because the other threads were started after the Map was fully populated so I think it is ok to access the Map from multiple threads as it cannot be modified after this point.

Yes. Just make sure that the other threads are started in a synchronized manner, i.e. make sure you have a happens-before relation between publishing the map, and starting the threads.

This is discussed in this blog post:

[...] This is how Collections.unmodifiableMap() works.

[...]

Because of the special meaning of the keyword "final", instances of this class can be shared with multiple threads without using any additional synchronization; when another thread calls get() on the instance, it is guaranteed to get the object you put into the map, without doing any additional synchronization. You should probably use something that is thread-safe to perform the handoff between threads (like LinkedBlockingQueue or something), but if you forget to do this, then you still have the guarantee.

Upvotes: 2

vidstige
vidstige

Reputation: 13077

You are correct. There is no need to ensure exclusive access to the data structure by different threads by using mutex'es or otherwise since it's immutable. This usually greatly increases performance.

Also note that if you only wrap the original Map rather than creating a copy, ie the unmodifiable Map delegates method calls further to the inner HashMap, modifying the underlying Map may introduce race condition problems.

Upvotes: 1

BalusC
BalusC

Reputation: 1108972

This is perfectly fine concerning the map itself. But you need to realize the making the map unmodifiable will only make the map itself unmodifiable and not its keys and values. So if you have for example a Map<String, SomeMutableObject> such as Map<String, List<String>>, then threads will still be able to alter the value by for example map.get("foo").add("bar");. To avoid this, you'd like to make the keys/values immutable/unmodifiable as well.

Upvotes: 11

Related Questions