If the read has not been synchronized, then the Hashtable can be modified while the read is in progress. New elements can be added, the base array can become too small and can be replaced with larger ones, etc. Without consistent execution, these situations are difficult to handle.
However, even if get does not fail when the Hashtable is modified by another thread, there is another important aspect of the synchronized , namely: cache synchronization. Let us use a simplified example:
class Flag { bool value; bool get() { return value; }
set synchronized, but get not. What happens if two streams A and B are simultaneously read and written to this class?
1. A calls read 2. B calls set 3. A calls read
Is it guaranteed in step 3 that A sees a modification of thread B?
No, this is not so, since A can run on a different kernel that uses a separate cache, where the old value is still present. Thus, we are forced to B associate memory with another core and force A to retrieve new data.
How can we enforce it? Each time a thread enters and leaves a synchronized block, an implicit memory barrier is executed. A memory failure causes the cache to update. However, it is required that both the writer and the reader must fulfill the memory barrier. Otherwise, the information is not transmitted properly.
In our example, thread B already uses the synchronized set method, so its data modification is reported at the end of the method. However, A does not see the changed data. The solution is to do get synchronization, so it is forced to receive updated data.