The following article contains one of the most important concepts of Java, Synchronisation in Java, along with simple examples to get a proper idea of the concept.
Synchronization in Java
Basically Synchronization in Java is the process of allowing the threads to execute one after the other. It controls the access of multiple threads to a shared resource.
Java is a multithreaded language where multiple threads can run in parallel to execute the program. In a multithreaded environment there is a necessity for synchronization of Java objects that share common resources concurrently. When two or more threads start within a program then there may be a situation of inconsistent results due to concurrency issues since multiple threads try to access the same resource at the same time.
Suppose multiple threads try to do a write operation; that may corrupt the data because one of the threads may overwrite the data or while one of the threads is opening the file at a time and another is closing the same file at the same time.
So there is a need for synchronization that ensures that only one thread can access the resource at a given time. This can be done by using the concept called monitor. In Java each object is associated with a monitor that a thread can lock or unlock. Only one thread can hold or lock at a time on a monitor.
The following is the syntax of a synchronization block:
synchronized(object identifier)
{
// access shared variables and other shared resources
}
An object identifier is a reference to an object whose lock associates with the monitor that the synchronized statement represents.
The Synchronized keyword provides locking that ensures the mutual exclusion access of shared resources and prevents the data race.
When a thread invokes a synchronization method, it automatically acquires a lock for that object and releases it when the method returns the chance to the next thread.
Example without Synchronization
Now let's see an example of multithreading without synchronization and analyse what happens without synchronization.
class Serial
{
void serialDisplay(int n)
{
// method is not synchronized
for(int i=1;i<=5;i++)
{
System.out.println("Thread "+i+" is :"+(n*i));
try
{
Thread.sleep(300);
}
catch(Exception e)
{
System.out.println("Thread interrupted"+e);
}
}
}
}
class Thread1 extends Thread
{
Serial s;
Thread1(Serial s)
{
this.s=s;
}
public void run()
{
s.serialDisplay(10);
}
}
class Thread2 extends Thread
{
Serial s;
Thread2(Serial s){
this.s=s;
}
public void run()
{
s.serialDisplay(50);
}
class ThreadTest
{
public static void main(String args[])
{
Serial no=new Serial();
Thread1 t1=new Thread1(no);
Thread2 t2=new Thread2(no);
t1.start();
t2.start();
// wait for threads to end
try
{
t1.join();
t2.join();
}
catch(Exception e)
{
System.out.println("Interrupt occurred"+e);
}
}
}
Output
Thread 1 is :10
Thread 1 is :50
Thread 2 is :100
Thread 2 is :20
Thread 3 is :30
Thread 3 is :150
Thread 4 is :200
Thread 4 is :40
Thread 5 is :250
Thread 5 is :50
Here, you can see that without synchronization method the output result is inconsistent.
This can produce a different result every time the program is run.
Example with Synchronization
Now let's have a look at the same example explained above with a slight change, now with synchronization and watch the difference between the two.
Just make change in the following line of code:
synchronized void serialDisplay(int n)
{
// method is now synchronized
}
Add the keyword synchronization before void serialDisplay(int n) as shown above and you will get the synchronised output that is shown below.
Output after making change
Thread 1 is :10
Thread 2 is :20
Thread 3 is :30
Thread 4 is :40
Thread 5 is :50
Thread 1 is :50
Thread 2 is :100
Thread 3 is :150
Thread 4 is :200
Thread 5 is :250
Now you can see the threading that is synchronized so properly that it looks like every thread gets the chance to execute one after the other.