Synchronization is done in order to protect a segment of code from being accessed by more than a single Thread at any particular instance of time. In Java, synchronization is achieved with the use of synchronized keyword. Synchronization can be applied to methods as well as to a block of code.
also read:
- Java Tutorials
- Java EE Tutorials
- Design Patterns Tutorials
- Java File IO Tutorials
The following code shows how to apply synchronization at the method level or to a block of code.
//Synchronizing a method public synchronized void myMethod() { // perform some operation }
//Synchronizing a block of code synchronized(this) { // perform some operation }
When synchronization is applied to a method or a code block, the first Thread that accesses it would have a lock on it on that particular object which was used to invoke it. This lock would be released only after the first Thread completes its execution of that method or a code block.If any other threads have to access the same method or block of code on the same object instance, then they have to wait till the current thread accessing it completes execution and releases the lock on it.Consider the following class which models a shared data and it is expected to be accessed by one or more thread. Given below is the code snippet for the Shared Data class.
SharedData.java
public class SharedData{ private String data = "HAPPY"; public void accessData(){ for(int i =0; i<20; i++){ data = data + " " + i + " "; } System.out.println(data); } }
And here is the Thread code that tries to access the shared data.
MyThread.java
public class MyThread extends Thread{ private SharedData data; public MyThread(SharedData data){ this.data = data; } public void run(){ data.accessData(); } }
Let us initiate the above process by creating one or more threads and then to access on the shared data.
ThreadSynchronizationTest.java
public class ThreadSynchronizationTest { public static void main(String[] args) { SharedData data = new SharedData(); MyThread one = new MyThread(data); one.start(); MyThread two = new MyThread(data); two.start(); } }
Actually, the expected results for this code is as follows,
HAPPY 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 HAPPY 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
But, since the accessData() method is accessed by two different threads on the same instance of ShareData. The results in this case would be like,
HAPPY 0 1 2 3 4 5 6 7 8 9 10 11 12 13 0 1 2 3 4 HAPPY 0 1 2 3 4 5 6 7 8 9 10 11 12 13 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
This is not the expected result and the cause for this is two threads have accessed the same method simultaneously without proper synchronization.
Let us see how the same code works when synchronization is applied to it, by the use of synchronized keyword for the method accessData().
public synchronized void accessData(){ for(int i =0; i<20; i++){ data = data + " " + i + " "; } System.out.println(data); } }
Since synchronization has been applied to the method accessData()
, we get the proper expected results which is as follows,
HAPPY 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 HAPPY 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Synchronization is aimed at making an object thread-safe. But, before going for it, we have to know that performance would be slow when we use synchronized methods. Since overheads such as Object locks are a part of synchronization, invoking a synchronized method or block of code is considerably slower than invoking a non-synchronized method or block of code.
Hence, it is advised to analyze based on the application and ensure whether Synchronization is needed or not.