When we start two or more threads within a program, there may be a situation when multiple threads try to access the same resource and finally they can produce unforeseen result due to concurrency issue.
For example if multiple threads try to write within a same file then they may corrupt the data because one of the threads can overrite data or while one thread is opening the same file at the same time another thread might be closing the same file.
The problems arise when multiple threads access the same resources - the same memory (variables, arrays, or objects), systems (databases, web services etc.) or files.
To prevent race conditions from occurring you must make sure that the critical section is executed as an atomic instruction. That means that once a single thread is executing it, no other threads can execute it until the first thread has left the critical section.
Synchronization in Java will only be needed if shared object is mutable.
So there is a need to synchronize the action of multiple threads and make sure that only one thread can access the resource at a given point in time.
This is implemented using a concept called monitors.
Each object in Java is associated with a monitor, which a thread can lock or unlock. Only one thread at a time may hold a lock on a monitor.
In Java, two synchronization strategies are used to prevent thread interference and memory consistency errors:
Includes the synchronized keyword in its declaration.
When a thread invokes a synchronized method, synchronized method automatically acquires the intrinsic lock for that method's object and releases it when the method returns, even if that return was caused by an uncaught exception.
Declares a block of code to be synchronized.
Unlike synchronized methods, synchronized statements should specify the objects that provide the intrinsic lock.
These statements are useful for improving concurrency with fine-grained synchronization, as they enable the avoidance of unnecessary blocking.
The synchronized keyword can be used to mark four different types of blocks:
- Instance methods (each instance has its synchronized methods synchronized on a different object)
- Static methods (synchronized static methods are synchronized on the class object of the class the synchronized static method belongs to)
- Code blocks inside instance methods
- Code blocks inside static methods
In Summary Java synchronized Keyword provides following functionality essential for concurrent programming:
- synchronized keyword in Java provides locking, which ensures mutual exclusive access of shared resource and prevent data race.
- synchronized keyword also prevent reordering of code statement by compiler which can cause subtle concurrent issue if we don't use synchronized or volatile keyword.
- synchronized keyword involve locking and unlocking. Before entering into synchronized method or block thread needs to acquire the lock, at this point it reads data from main memory than cache and when it release the lock, it flushes write operation into main memory which eliminates memory inconsistency errors.
Important points of synchronized keyword in Java
- Synchronized keyword in Java is used to provide mutual exclusive access of a shared resource with multiple threads in Java.
- You can use java synchronized keyword only on synchronized method or synchronized block.
- Whenever a thread enters into java synchronized method or block it acquires a lock and whenever it leaves java synchronized method or block it releases the lock.
- Java Thread acquires an object level lock when it enters into an instance synchronized java method and acquires a class level lock when it enters into static synchronized java method.
- Java synchronized keyword is re-entrant in nature it means if a java synchronized method calls another synchronized method which requires same lock then current thread which is holding lock can enter into that method without acquiring lock.
- Java Synchronization will throw NullPointerException if object used in java synchronized block is null e.g. synchronized (myInstance) will throws java.lang.NullPointerException if myInstance is null.
- One Major disadvantage of Java synchronized keyword is that it doesn't allow concurrent read, which can potentially limit scalability. By using concept of lock stripping and using different locks for reading and writing, you can overcome this limitation of synchronized in Java.
- One more limitation of java synchronized keyword is that it can only be used to control access of shared object within the same JVM. If you have more than one JVM and need to synchronized access to a shared file system or database, the Java synchronized keyword is not at all sufficient. You need to implement a kind of global lock for that.
- Java synchronized keyword incurs performance cost. Synchronized method in Java is very slow and can degrade performance. So use synchronization in java when it absolutely requires and consider using java synchronized block for synchronizing critical section only.
- Java synchronized block is better than java synchronized method in Java because by using synchronized block you can only lock critical section of code and avoid locking whole method which can possibly degrade performance.
- Its possible that both static synchronized and non static synchronized method can run simultaneously or concurrently because they lock on different object.
- From java 5 after change in Java memory model reads and writes are atomic for all variables declared using volatile keyword (including long and double variables) and simple atomic variable access is more efficient instead of accessing these variables via synchronized java code.
- According to the Java language specification you can not use Java synchronized keyword with constructor.
- You cannot apply java synchronized keyword with variables and can not use java volatile keyword with method.
- Java.util.concurrent.locks extends capability provided by java synchronized keyword for writing more sophisticated programs since they offer more capabilities e.g. Reentrancy and interruptible locks.
- Java synchronized keyword also synchronizes memory. In fact java synchronized synchronizes the whole of thread memory with main memory.