Thread Synchronization

When multiple threads operate over same java object then there is a chance of data inconsistency problem hence Thread Synchronization came into picture.

  • Synchronized is the modifier applicable only for methods and blocks but not for classes and variables.
  • If multiple threads are trying to operate simultaneously on the same java object then there may be chance of data inconsistency problem, to overcome this problem we should go for synchronized keyword.
  • If a method or block is declared as synchronized, then at a time only one thread is allowed to execute that method or block on the given object so that data inconsistency problem will be resolved.
  • The main advantage of synchronized keyword is we can resolve data inconsistency problems but the main disadvantage synchronized keyword is it increases waiting time of thread and creates performance problems. Hence if there is no specific requirement then it is not recommended to use synchronized keyword.
  • Internally synchronization concept is implemented by using lock, every object in java has a unique lock.
  • When ever we are using synchronized keyword then only lock concept will come into picture.
  • If a thread wants to execute synchronized method on the object first it has to get lock of that object, once thread got the lock of that object then it is allowed to execute any synchronized method on that object.
  • Once method execution completes automatically thread releases the lock. Acquiring and releasing lock internally is taken care by JVM and programmer not responsible for this activity.
  • While a thread executing synchronized method on a given method then the remaining threads are not allowed to execute any synchronized method simultaneously on the same object but remaining threads are allowed to execute non synchronized methods simultaneously.

Below example shows how all the 4 threads are executed one after another because of the synchronized keyword.

package com.demo1;

public class ThreadNameDemo {
	
	public static void main(String[] args) throws InterruptedException {
		TempThread temp = new TempThread();
		Thread t1 = new Thread(temp);
		Thread t2 = new Thread(temp);
		Thread t3 = new Thread(temp);
		Thread t4 = new Thread(temp);
		t1.start();
		t2.start();
		t3.start();
		t4.start();
		System.out.println("Thread stopped");
	} 
}
class TempThread implements Runnable{
	@Override
	public synchronized void run() {
		try {
			for(int i=0; i<3;i++) {
				System.out.println(Thread.currentThread().getName()+" - "+i);
				Thread.sleep(10);
			}
		}catch(InterruptedException e) {
			System.out.println("InterruptedException has been caught : "+e);
		}
	}
}
  • While a thread executing synchronized method on an given object the remaining threads(executing same object) are not allowed to execute any other synchronized method simultaneously on the same object, but remaining threads are allowed to execute non synchronized methods simultaneously.
    Example Below :
package com.demo1;

public class ThreadDemo extends Thread{
	public static void main(String[] args) {
		Print p = new Print(2);
		new Thread(new PrintMultiplicationRunnable(p)).start();
		new Thread(new PrintSquareRunnable(p)).start();
		new Thread(new PrintAdditionRunnable(p)).start();
	}
}
class Print{
	int number;
	Print(int x){
		number = x;
	}
	public int getNumber() {
		return number;
	}
	public void setNumber(int number) {
		this.number = number;
	}
	void prinAdditionTables(int x) throws InterruptedException {
		int i;
		for(i=1;i<=10;i++) {
			System.out.println(x +" + "+i+" = "+x+i+" - non synchronized  method");
			Thread.sleep(500);
		}
	}
	synchronized void printMultiplicationTables(int x) throws InterruptedException {
		int i;
		for(i=1;i<=10;i++) {
			System.out.println(x +" x "+i+" = "+x*i+" synchronized method - 1 ");
			Thread.sleep(100);
		}
	}
	synchronized void printSquares(int x) throws InterruptedException {
		int i,j,temp;
		for(i=1;i<=10;i++) {
			temp=1;
			for(j=1;j<=x;j++) {
				temp = i * temp;
			}
			System.out.println(" Value : "+temp+" synchronized method - 2 ");
			Thread.sleep(100);
		}
	}
}
class PrintAdditionRunnable implements Runnable {
	Print p;
	PrintAdditionRunnable(Print p){
		this.p = p;
	}
	@Override
	public void run() {
			try {
				p.prinAdditionTables(p.getNumber());
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
	}
}
class PrintMultiplicationRunnable implements Runnable{
	Print p;
	PrintMultiplicationRunnable(Print p){
		this.p = p;
	}
	@Override
	public void run() {
		try {
			p.printMultiplicationTables(p.getNumber());
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}
class PrintSquareRunnable implements Runnable{
	Print p;
	PrintSquareRunnable(Print p){
		this.p = p;
	}
	@Override
	public void run() {
		try {
			p.printSquares(p.getNumber());
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

As you can see in the above example method 1 and method 2 are two different synchronized method of a class but both are executed one after another only because during an execution of a synchronized method object level lock is acquired by the thread and no other synchronized method of that object can be execute by any thread at that point of time. But all the non synchronized method are free to execute at any point of time no lock is required for it.

Note : Wherever we are performing update operation(Add/Remove/Delete/Replace) that changes the state of object we should be adding synchronized method to it.

Example 2 :

package com.demo1;

import java.util.stream.IntStream;

public class HelloThreadDemo {
	public static void main(String[] args) {
		Greet greet = new Greet();
		GreetThread t1 = new GreetThread(greet,"Tyson");
		GreetThread t2 = new GreetThread(greet,"Justin");
		GreetThread t3 = new GreetThread(greet,"Martin");
		t1.start();
		t2.start();
		t3.start();
	}
}

class Greet{
	synchronized public void wish(String name) {
		IntStream.range(0,10).forEach(x -> System.out.println(name +" "+x));
	}
}
class GreetThread extends Thread{
	Greet greet;
	String name;
	GreetThread(Greet greet,String name){
		this.greet = greet;
		this.name = name;
	}
	public void run() {
		greet.wish(name);
	}
}

If we are not declaring wish method as synchronized then all the three threads will be executed simultaneously the output will be some like this below.

Static Synchronized method

Class level lock : Every class in java has a unique lock which is nothing but class level lock.

If a thread wants to execute a static synchronized method then thread requires class level lock, once thread got class level lock then it is allowed to execute any static synchronized method of that class. Once method execution completes automatically thread releases the lock.

Important :

  • While a thread executing static synchronized method the remaining threads are not allowed to execute any static synchronized method since class level lock is already acquired by one of the method.
  • But remaining threads are allowed to execute the following method simultaniously
    • Normal static method
    • Synchronized instance methods
    • Normal instance methods.
package com.demo1;

import java.util.stream.IntStream;

public class HelloThreadDemo {
	public static void main(String[] args) {
 		GreetThread t1 = new GreetThread( new Greet(),"Tyson");
		GreetThread t2 = new GreetThread( new Greet(),"Justin");
		GreetThread t3 = new GreetThread( new Greet(),"Martin");
		t1.start();
		t2.start();
		t3.start();
	}
}

class Greet{
	public static synchronized void wish(String name) {
		IntStream.range(0,10).forEach(x -> System.out.println(name +" "+x));
	}
}
class GreetThread extends Thread{
	Greet greet;
	String name;
	GreetThread(Greet greet,String name){
		this.greet = greet;
		this.name = name;
	}
	public void run() {
		greet.wish(name);
	}
}

Leave a Comment