Synchronization in java

In this post, we will learn synchronization in java, and why we need Java synchronization, how to write synchronized code and more important points about synchronization.

Here is the table content of the article will we will cover this topic.
1. Synchronization in java?
2. Why do we use Synchronization in Java?
3. Locks in Java?
4. Types of Synchronization?
5. Multi-threading without Synchronization?
6. Multi-threading with Synchronization?
7. Important points about java synchronized?

8. Java synchronized block
i) synchronized block in non-static method
ii) synchronized block in static method

9. Java synchronized method
i) Java synchronization with non-static method
ii) Java synchronized method

Synchronization in java

In a multithreading environment, multiple threads can try to access the same resources and can produce erroneous and unforeseen results. Java provides a way to control the access of multiple threads to any shared resource. Synchronization in java is a process where we want to allow only one thread to access the shared resource at a time. So that multiple threads can work together without creating any problems. The synchronization process can achieve by synchronized keyword in java. The Synchronization keyword makes the code thread-safe.

Synchronization in java

Why do we use Synchronization in Java?

Suppose you have two resources and there may be a chance when multiple threads try to attempt the same resource and produce errors. So synchronization is used to handle the following errors:

1. Thread Interference Error: The thread interference error occurs when we have more than one thread and they are running simultaneously.  Because they want to access the same piece of data and perform different operations on the same data. The operation of one thread could overlap with another thread and leads to data inconsistency.

2. Memory Consistency Error: The memory Consistency Error occurs when the changes made by one thread may not be visible to the other threads. The other threads have inconsistent views of the same shared data.

Locks in Java

Before moving further in synchronization, we have to understand the concept of lock or monitor. In java, Each and every object has a lock associated with it. When multiple threads access the shared resource, they use the lock. A thread requests a lock to an object and access data from the object meanwhile all other thread waits to release the lock. A thread releases the lock after the completion of work.

Types of Synchronization

There are 2 types of synchronization in java as shown below:

1. Process Synchronization: The simultaneous execution of multiple threads or processes to reach a state such that they commit to a certain sequence of actions.

2. Thread Synchronization: Thread Synchronization allows to access the shared space only one thread at a time.

In this post, we will discuss thread synchronization. The thread synchronization is divided into two parts.

1. Mutual Exclusive:  Mutual exclusion is the simplest type of thread synchronization. This synchronization allows only one thread can execute the shared resource at a time. When a thread accesses the shared resource, it takes a lock and all other threads wait to release the lock.  Let’s read how we can achieve it. There are two ways
1. Synchronized method.
2. Synchronized block.

2. Cooperation (Inter-thread communication in java): Interthread communication in java is used to avoid polling and is important when you want to develop an application where two or more threads exchange some information. Java provides three methods that are used for inter-thread communication. Those methods are,  wait(), notify() and notifyAll() and these methods belong to the object class.

Multi-threading without Synchronization

Let’s discuss an example that prints the count by two different threads.

class Count
{  
	void printTable(int n)
	{
		//method not synchronized  
	   for(int i=1;i<=5;i++)
	   {  
	     System.out.println(n*i);  
	     try
	     {  
	       Thread.sleep(400);  
	     }
	     catch(Exception e){System.out.println(e);}  
	   }  
	  
	 }  
}  
  
class MyThread1 extends Thread
{  
	Count c;  
	MyThread1(Count c)
	{  
		this.c=c;  
	}  
	public void run()
	{  
		c.printTable(5);  
	}  
	  
}  
class MyThread2 extends Thread
{  
	Count c;  
	MyThread2(Count c)
	{  
		this.c=c;  
	}  
	public void run()
	{  
		c.printTable(100);  
	}  
}  
  
public class WithoutSynchronization
{  
	public static void main(String args[])
	{  
		Count obj = new Count();//only one object  
		MyThread1 t1=new MyThread1(obj);  
		MyThread2 t2=new MyThread2(obj);  
		t1.start();  
		t2.start();  
	}  
}  

Output: 5
100
200
10
15
300
400
20
500
25

Multi-threading with Synchronization

class Count
{  
	synchronized void printTable(int n)
	{
		//method not synchronized  
	   for(int i=1;i<=5;i++)
	   {  
	     System.out.println(n*i);  
	     try
	     {  
	       Thread.sleep(400);  
	     }
	     catch(Exception e){System.out.println(e);}  
	   }  
	  
	 }  
}  
  
class MyThread1 extends Thread
{  
	Count c;  
	MyThread1(Count c)
	{  
		this.c=c;  
	}  
	public void run()
	{  
		c.printTable(5);  
	}  
	  
}  
class MyThread2 extends Thread
{  
	Count c;  
	MyThread2(Count c)
	{  
		this.c=c;  
	}  
	public void run()
	{  
		c.printTable(100);  
	}  
}  
  
public class WithSynchronization
{  
	public static void main(String args[])
	{  
		Count obj = new Count();//only one object  
		MyThread1 t1=new MyThread1(obj);  
		MyThread2 t2=new MyThread2(obj);  
		t1.start();  
		t2.start();  
	}  
}  

Output: 5
10
15
20
25
100
200
300
400
500

Important points about java synchronized

1. Synchronized keyword in Java is used to synchronize the shared resource when multiple threads use it. Synchronization in Java is used to remove thread interference and memory inconstancy.

2. Java allows us to use the synchronized keyword with a method or block.

3. The concept of synchronization works based on lock. Whenever a thread enters into a java synchronized method or blocks it acquires a lock and releases the lock after completion of execution.

4. When a thread enters into a non-static synchronized method, it acquires an object-level lock. But when the thread enters into a static synchronized java method it acquires a class-level lock.

5. when a java synchronized method calls another synchronized method then it requires the same lock. But the current thread can enter without a lock because it already holding the lock.

6. Synchronized block throws NullPointerEception, if the object used in the java synchronized block is null.

7.  A synchronized method is slow and can degrade performance because threads have to wait for their turn.

8. It is always better to use the Java synchronized block instead of the synchronized method because the using synchronized block only locks critical section of code and avoid locking the whole method.

9. The static synchronized and non-static synchronized method can run simultaneously because they lock on different objects.

Java synchronized method

We have read synchronization in java and Java block synchronization. Multiple threads used the shared resources and access the fields and objects reference fields. But it can create a problem with data inconsistency or thread interference. We prevent these errors by use of synchronized keyword in java.  Let’s read the Java synchronized method.

To achieve the synchronization in java we can use the java synchronized keyword with the method. A synchronized method is used to ensure that only one thread can execute it at a time. As we discussed each object has a lock or monitor, so when any thread accesses it, the thread performs certain operations:   

1. A thread checks the lock of the synchronized method. If there no other thread is executing it then the lock will be available.

2. If the lock is available, the thread takes the lock and performs the operation as per requirements. Meanwhile, all the other thread waits for the lock.

3. Multiple threads can’t take a lock at the same time.

The synchronized keyword can be used with a static method and a non-static method(instance methods). Here we will see the static and non-static synchronized method in java.

1. Java synchronization with non-static method

A synchronized non-static method is synchronized on the object level. If the method is non-static, the lock is acquired on the current object. Each object has its synchronized methods and only one thread per object can execute inside a synchronized method.  It is also known as object-level locking.

Syntax of synchronized Method

access_modifiers synchronized return_type method_name(method_parameters)
{ 
     // method_code 
}

Let’s see thread synchronization in java simple example

class Test 
{ 
    synchronized public void count() 
    { 
        for (int i = 0; i < 3; i++) 
        { 
            System.out.println(i); 
            try 
            { 
                Thread.sleep(400); 
            } 
            catch (Exception e) 
            { 
                System.out.println(e); 
            } 
        } 
    } 
} 
  
class MyThread extends Thread { 
   
    Test test; 
  
    MyThread (Test test) { 
        this.test = test; 
    } 
  
    @Override
    public void run() { 
        test.count(); 
    } 
} 
  
public class SynchronizedMethod 
{ 
    public static void main(String[] args) 
    { 
        Test obj = new Test(); //Object of Apple class that is shared amoung threads
  
        MyThread thread1 = new MyThread(obj); 
        MyThread thread2 = new MyThread(obj); 
  
        thread1.start(); 
        thread2.start(); 
    } 
} 

Output: 0
1
2
0
1
2

In the above example, we are creating two threads thread1 and thread2. Both are using the synchronized count()  method. As it is synchronized, both are using it one by one. Firstly,  thread1 enters the count() method and gets a lock meanwhile thread2 waits until thread1 finishes the execution. and release the lock. After that thread2 gets the lock and completes the execution.

2. Java synchronized static method

As we know static methods belong to a class instead of an object. When we use a synchronized keyword with a static method, the lock is acquired in the class. In synchronized static methods only one thread can execute inside a static synchronized method in the same class. If we have more than one static synchronized method, then only one thread can execute any of these methods at the same time.
Suppose we have two static synchronized methods, method1 and method2, and two threads thread1 and thread2. Here thread1 or thread2 can execute only one static method.

Syntax of static synchronized Method

access_modifiers synchronized static return_type method_name(method_parameters)
{ 
    // method_code 
}
class Test 
{ 
    synchronized static public void countIncrement() 
    { 
    	System.out.println("Increment values");
        for (int i = 0; i < 3; i++) 
        { 
            System.out.println(i); 
            try 
            { 
                Thread.sleep(400); 
            } 
            catch (Exception e) 
            { 
                System.out.println(e); 
            } 
        } 
    } 
    synchronized static public void countDecrement() 
    { 
    	System.out.println("Decrement values");
        for (int i = 3; i > 0; i--) 
        { 
            System.out.println(i); 
            try 
            { 
                Thread.sleep(400); 
            } 
            catch (Exception e) 
            { 
                System.out.println(e); 
            } 
        } 
    } 
} 
  
class MyThread extends Thread { 
   
    Test test; 
  
    MyThread (Test test) { 
        this.test = test; 
    } 
  
    @Override
    public void run() { 
        test.countIncrement(); 
        test.countDecrement();
    } 
} 
  
public class SynchronizedMethod 
{ 
    public static void main(String[] args) 
    { 
        Test obj = new Test(); //Object of Apple class that is shared amoung threads
  
        MyThread thread1 = new MyThread(obj); 
        MyThread thread2 = new MyThread(obj); 
  
        thread1.start(); 
        thread2.start(); 
    } 
} 

Output: Increment values
0
1
2
Increment values
0
1
2
Decrement values
3
2
1
Decrement values
3
2
1

In the above example, we have two static synchronized methods (countIncrement() method and countDecrement() method) and two threads(thread1 and thread2). One thread can access only one static method at a time.

Java synchronized block

We have read synchronization in java and method synchronization with synchronized keyword. In method synchronization, we synchronized the whole code of the method. But sometimes we want to synchronize a portion of a method, not the whole method. For such types of situations, we should use Java synchronized block. In this post, we will read it in detail.

The Java synchronized block is used to synchronize a portion of code or set of statements. Like the synchronized method, synchronized blocks in Java are marked with the synchronized keyword. A synchronized block can be executed by only one thread at a time and all other threads wait for the completion of execution.

synchronized ( lockObject)
{
       //synchronized statements
}

A thread can execute the synchronized block only to acquire the lock on lockObject. Only one thread can acquire the monitor of a lock object at a time meanwhile all other threads wait for the lock.  

We can have two types of synchronized blocks.

1. synchronized block in non-static method

When you want to synchronize a portion of the method instead of the whole method. We can use a synchronized block of Java code inside an unsynchronized Java method.

access_modifiers return_type method_name(method_parameters)
{ 
       synchronized (objLock) 
       {
             // block of code
        }
        // method_code 
}

You must think about why the synchronized block construct takes an object in parentheses. This object is known as the monitor object. Only one thread can execute inside a Java code block synchronized on the same monitor object.

class Test 
{ 
    public void countIncrement() 
    { 
    	synchronized(this)
    	{
	        for (int i = 0; i < 3; i++) 
	        { 
	            System.out.println(i); 
	            try 
	            { 
	                Thread.sleep(400); 
	            } 
	            catch (Exception e) 
	            { 
	                System.out.println(e); 
	            } 
	        } 
    	}
    } 
} 
  
class MyThread extends Thread { 
   
    Test test; 
  
    MyThread (Test test) { 
        this.test = test; 
    } 
  
    @Override
    public void run() { 
        test.countIncrement(); 
    } 
} 
  
public class SynchronizedMethod 
{ 
    public static void main(String[] args) 
    { 
        Test obj = new Test(); 
  
        MyThread thread1 = new MyThread(obj); 
        MyThread thread2 = new MyThread(obj); 
  
        thread1.start(); 
        thread2.start(); 
    } 
} 

Output: 0
1
2
0
1
2

2. synchronized block in static method

We can use the Synchronized blocks inside the static method. Suppose if we have two static methods with a synchronized block then only one thread can execute inside any of these two methods at the same time.

class Test 
{ 
    synchronized static public void countIncrement() 
    { 
    	synchronized (Test.class) 
    	{
    		System.out.println("Increment values");
            for (int i = 0; i < 3; i++) 
            { 
                System.out.println(i); 
                try 
                { 
                    Thread.sleep(400); 
                } 
                catch (Exception e) 
                { 
                    System.out.println(e); 
                } 
            } 
		}
    	
    } 
    synchronized static public void countDecrement() 
    { 
    	synchronized (Test.class) 
    	{
	    	System.out.println("Decrement values");
	        for (int i = 3; i > 0; i--) 
	        { 
	            System.out.println(i); 
	            try 
	            { 
	                Thread.sleep(400); 
	            } 
	            catch (Exception e) 
	            { 
	                System.out.println(e); 
	            } 
	        } 
    	}
    } 
} 
  
class MyThread extends Thread { 
   
    Test test; 
  
    MyThread (Test test) { 
        this.test = test; 
    } 
  
    @Override
    public void run() { 
        test.countIncrement(); 
        test.countDecrement();
    } 
} 
  
public class SynchronizedMethod 
{ 
    public static void main(String[] args) 
    { 
        Test obj = new Test(); //Object of Apple class that is shared amoung threads
  
        MyThread thread1 = new MyThread(obj); 
        MyThread thread2 = new MyThread(obj); 
  
        thread1.start(); 
        thread2.start(); 
    } 
} 

Output: Increment values
0
1
2
Increment values
0
1
2
Decrement values
3
2
1
Decrement values
3
2
1

Leave a Comment