Java compiler is free to re-arrange the instructions provided by our java program in the name of optimization.
There are many cases where access to the variables can occur in an order than specified in the program.
A straight-forward example is:
A thread T has to write a value to a variable _va and then to a variable _vb, and if _vb is not dependent on _va, the compiler can reorder these write instructions.Write to _vb can happen before a write to _va.
In general instruction re-orders cannot be a problem in single-threaded programs but when it comes to multi-threaded programs, the re-orders can result in data race (inconsistent data) if not properly synchronized.
To ensure that any thread at any time gets the updated value/state of an object (updated by other threads), our program must have read/write operations that comply with happens-before relationship.
In simple, happens-before relationship guarantees that memory writes in one specific statement is visible to another specific statement.
Some of the actions that create happens-before relationship are:
We also have certain other actions that creates happens-before relationship.
Synchronization is an action that can effectively prevent data race and state inconsistency. Synchronized Methods & Synchronized Statements are 2 ways that Java provides to implement this synchronization action.
These 2 provisions automatically establish happens-before relationship.
How synchronized method works:
Any object in java exists with an implicit/intrinsic lock. When a thread enters a synchronized method of an object it is this lock which it acquires. Other threads must wait for that lock gets released. When the synchronized method is static the implicit lock of the class is used.
Any arbitrary thread that waits for that lock will be intimated and enter the synchronized method. This synchronize action ensures that any write that happened inside the synchronized method is visible to the new thread entering the synchronized method.
How synchronized statements works:
Synchronized statements provide a more granularity over the counterpart. With this provision you can mark a set of statements as a synchronized block and at any time only one thread can enter this block. Unlike synchronized methods, the synchronized statements must specify the object that provides the implicit lock.
Examples for synchronization will follow....