0

I have a HashMap which is shared among multiple threads. And any thread can update it. So I synchronise on HashMap object while updating it.

Should I synchronise while reading too ? OR just making it volatile is enough ?

Note: I know I could simply use ConcurentHashMap but want to know whether multi threading affects reading of shared resources which are mutable . If yes, how it affects ?

Also what if it is a simple object (not a collection) or a primitive type.

SME
  • 23
  • 7
  • Note that making the map `volatile` will only guarantee visibility of the reference. It won't guarantee visibility for the stored values. The answer: [Do you need to synchronized reading from HashMap?](https://stackoverflow.com/questions/33987181/do-you-need-to-synchronized-reading-from-hashmap) – akuzminykh Aug 07 '20 at 11:33
  • @akuzminykh I read the answer . But could you explain why it results in an inconsistency while reading ? Does this apply to all other types of resource ? – SME Aug 07 '20 at 11:41
  • A Java HashMap is a fairly complex data structure. Why do you think it can be safely read while it's being modified? – Andrew Henle Aug 07 '20 at 11:50
  • This is difficult (or at least time-consuming) to answer because one have to look into `HashMap` and see how exactly it works (probably all of it). Then you can tell what inconsistencies might occur if reads are not synchronized. Be on the safe side and synchronize it. – akuzminykh Aug 07 '20 at 11:51
  • While reading , all i want is to see the updated mappings ? And isn't read operation a single operation unlike update ? Actually i don't know how exactly it causes inconsistency. Please give me solid example @AndrewHenle – SME Aug 07 '20 at 11:55
  • @SME *And isn't read operation a single operation unlike update ?* Why would you think reading a HashMap with potentially many, many entries would be a single operation? The `get()` call needs to find the matching key, retrieve the related object, and return it. – Andrew Henle Aug 07 '20 at 11:59
  • @AndrewHenle. I agree with you . But in which case i would experience an inconsistency . Note that Update operation is atomic. – SME Aug 07 '20 at 12:02
  • @akuzminykh what would be the case if it is a primitive variable or a single object (not a collection) – SME Aug 07 '20 at 12:05
  • @SME Why would you say the update is atomic? An unsyncrhonized read operation can very well try reading when the HashMap is just partially updated. – Andrew Henle Aug 07 '20 at 12:07

3 Answers3

1

You need to synchronise while reading too, or switch to using a ConcurrentHashMap.

If one thread calls the get method while another thread is updating the map, it is impossible to predict what will happen. The get method may throw an exception, because it assumes that the internal structure of the map does not change while it's running.

Joni
  • 108,737
  • 14
  • 143
  • 193
  • But I am synchronising while updating the HashMap. So my update operation is atomic – SME Aug 07 '20 at 11:58
  • 2
    Synchronization does not mean atomicity. What you have is mutual exclusion among the update operations. You are allowing a thread to do a read while another thread is running an update. – Joni Aug 07 '20 at 12:04
1

The Java HashMap documentation states (bolding in the original):

Note that this implementation is not synchronized. If multiple threads access a hash map concurrently, and at least one of the threads modifies the map structurally, it must be synchronized externally. (A structural modification is any operation that adds or deletes one or more mappings; merely changing the value associated with a key that an instance already contains is not a structural modification.) This is typically accomplished by synchronizing on some object that naturally encapsulates the map. If no such object exists, the map should be "wrapped" using the Collections.synchronizedMap method. This is best done at creation time, to prevent accidental unsynchronized access to the map:

Map m = Collections.synchronizedMap(new HashMap(...));

The iterators returned by all of this class's "collection view methods" are fail-fast: if the map is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove method, the iterator will throw a ConcurrentModificationException. Thus, in the face of concurrent modification, the iterator fails quickly and cleanly, rather than risking arbitrary, non-deterministic behavior at an undetermined time in the future.

Note that the fail-fast behavior of an iterator cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast iterators throw ConcurrentModificationException on a best-effort basis. Therefore, it would be wrong to write a program that depended on this exception for its correctness: the fail-fast behavior of iterators should be used only to detect bugs.

You can not safely change a HashMap while reading from it. Can you safely climb a ladder while rungs are being removed?

Andrew Henle
  • 32,625
  • 3
  • 24
  • 56
  • Thank you. But is the case similar for a primitive type variable and single object (not collection) ? – SME Aug 07 '20 at 12:19
0

You should also synchronize the read side because any guarantees (visibility in your case) applies only when threads uses same lock, so when you skip synchronizing while reading - it means that reading thread doesn't use the same lock (it doesn't use any lock) which will lead to see stale values by reading thread. See here: Should getters and setters be synchronized?

minizibi
  • 363
  • 2
  • 14