2
votes

Section 3.5.4 discusses about effectively immutable objects, that is, once an object is safely and fully constructed, its state would not be changed by any code of any code-path.

Sir Goetz has given an example:

For example, Date is mutable, but if you use it as if it were immutable you may be able to eliminate the locking that would otherwise be required when shared[sharing] a Date across threads. Suppose you want to maintain a Map storing the last login time of each user:

public Map<String, Date> lastLogin = 
Collections.synchronizedMap(new HashMap<String, Date>());

If the Date values are not modified after they are placed in the Map, then the synchronization in the synchronizedMap implementation is sufficient to publish the Date values safely, and no additional synchronization is needed when accessing them.

The point that I am not able to understand is that why do we want to use synchronizedMap and bear the extra overhead of its internal lockings when we could have simply used unsafe Map, because after all we would be placing effectively immutable Date objects in it - which means, that once properly and fully constructed and published, it would not be mutated anymore. And so even if the Map itself be unsafe, there would be just no code in any of the code-paths which could concurrently mutate any Date instance while other thread(s) has retrieved it from the Unsafe Map.

To sum up, the very premise of effectively immutable objects does not necessitate need of any Thread-safe containers since we should just not have any mutator code in any code-path for effectively immutable objects.

2
Yes, Date itself is immutable. But you are calling map.put() from multiple threads. And map is not immutable. You are adding it it. - fukanchik
Without synchronisation, one thread reading the map would not be guaranteed to see the changes made by another thread. - assylias
@fukanchik: Date isn't immutable. What are you talking about? - Makoto
@Makoto read the question: Date is mutable, but if you use it as if it were immutable you may be able to eliminate the locking - fukanchik
@fukanchik: The main thing I'd like to stress here is that you don't want to call something immutable when it isn't. Date is infamously immutable; the phrasing you probably wanted to use was "effectively immutable". - Makoto

2 Answers

4
votes

If you use an un-synchronized mutable map and share it across threads then you will have two thread-safety issues :visibility and atomicity. Thread-1 wont know if Thread-2 has removed a Map-Entry or it replaced its value by a new Date object.

// not atmoic and doesn't guarantee visiblity
if(map.contains(key)){
 map.put(key,newDate); 
}
1
votes

The key phrase from the original text is, "fully constructed and published." "Published", in particular refers to making an object created by one thread visible to other threads, and when the object is not truly immutable, then it must be done safely (Google "Java safe publication").

Without synchronization, Java does not guarantee that updates to variables made by one thread will be seen by other threads or, in what order the updates will be seen.

In most computer architectures, providing a consistent view of shared memory to all of the threads is relatively expensive. By not requiring the threads to have a consistent view except when explicitly synchronizing, Java allows the threads to get a consistent view when it is needed, or to get the best performance possible when it is not needed.

Also, All of the above ignores the very real possibility that the program might need to synchronize accesses to the Map for other reasons (e.g., to prevent simultaneous updates from corrupting the Map itself.)