Synchronized block

  • If very few lines of code requires synchronization then it is not recommended to declare entire method as synchronized, we have to enclose those few lines of code by using synchronized block.
  • The main advantage of synchronized block over synchronized method is, it reduces waiting time of threads and improves performance of the application.

We can declare synchronized block as follows :

1. To get lock of current object

synchronized(this){
//line of codes
//If a thread got lock of current object then only it is allowed to execute this area
}

2. To get lock of particular object

synchronized(object){
//line of codes 
//If a thread got lock of particular object b then only it is allowed to execute this area
}

3. To get class level lock

synchronized(Display.class){
//line of codes
//If a thread got class level lock of display class then only it is allowed to execute this area
}

Example1 : (lock of current object)

package com.demo2;

import java.util.stream.IntStream;

public class ThreadDemo {
	public static void main(String[] args) {
		Greet greet = new Greet();
		new GreetThread(greet,"Tyson").start();
		new GreetThread(greet,"Justin").start();
		new GreetThread(greet,"Martin").start();
	}
}
class Greet{
	public void display(String name) {
		synchronized(this) {
			IntStream.range(1,5).forEach(x -> System.out.println(name+" : "+x));
		}
	}
}
class GreetThread extends Thread{
	String name;
	Greet greet;
	GreetThread(Greet greet,String name){
		this.greet = greet;
		this.name = name;
	}
	public void run() {
		greet.display(name);
	}
}

Example 2 : Lock of current class

package com.demo2;

import java.util.stream.IntStream;

public class ThreadDemo {
	public static void main(String[] args) {
		Greet greet = new Greet();
		new GreetThread(greet,"Tyson").start();
		new GreetThread(greet,"Justin").start();
		new GreetThread(greet,"Martin").start();
	}
}
class Greet{
	public void display(String name) {
		synchronized(Greet.class) {
			IntStream.range(1,5).forEach(x -> System.out.println(name+" : "+x));
		}
	}
}
class GreetThread extends Thread{
	String name;
	Greet greet;
	GreetThread(Greet greet,String name){
		this.greet = greet;
		this.name = name;
	}
	public void run() {
		greet.display(name);
	}
}

Note : Lock concept applicable for object types and class types but not for primitives hence we can’t pass primitive type as argument to synchronized block, other wise we will get compile time error saying unexpected type found int required reference.

Important Note :It’s possible that both static synchronized and non static synchronized method can run simultaneously or concurrently because they lock on different object.

FAQ :

  1. What is synchronized keyword where we can apply.
  2. Explain advantages of synchronized keyword.
  3. Explain disadvantages of synchronized keyword.
  4. What is race condition.
    If multiple threads access the same java object then it might cause data inconsistency problem, this is called as race condition.We can resolve it by using synchronized keyword.
  5. What is a object lock and when it is required?
  6. What is a class level lock and when it is required?
  7. What is the difference between class level and object level lock?
    While a thread executing synchronized method on the given object is the remaining thread allowed to execute any other synchronized method simultaneously on the same object

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 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);
	}
}

The methods to prevent Thread execution(Yield/Join/Sleep)

Yield Method

  • Yield method causes to pause the current executing thread to give the chance for waiting threads of same priority.
  • If there is no waiting thread or all waiting threads have low priority then same thread can continue its execution.
  • If multiple threads are waiting with same priority then which waiting thread will get the chance we cannot expect it depends on the thread scheduler.
  • The thread which is yielded when it will get the chance once again it depends on thread scheduler and we can predict it exactly.
  • If your schedular/processor does not support preemptive scheduling then yield method may not work on that platform.
public static native void yield();
public class ThreadNameDemo {
	public static void main(String[] args) {
		Thread t = new Thread(new TempThread());
		t.start();
		for(int i=0; i<10;i++) {
			Thread.yield();
			System.out.println("Main Thread : "+i);
		}
	} 
}
class TempThread implements Runnable{
	@Override
	public void run() {
		for(int i=0; i<10;i++) {
			Thread.yield();
			System.out.println("Child Thread : "+i);
		}
	}
}

Join Method

Case 1 : Main Thread Call join method on Child Thread Object (Main Thread waits for child thread to complete)

  • If a thread wants to wait until completing some other thread then we should go for join method.
  • For example : If a thread T1 wants to wait until completing T2 then T1 has to call T2.join()
  • If T1 executes T2.join() then immediately T will be entered into waiting state until T2 thread is completed.
  • Once T2 thread completes then T1 thread can continue its execution.
  • We can also ask a thread to wait for a thread for some fixed time, by passing the time parameter in the join() method.
  • If a Thread call a join() method on itself then the program will be stuck for ever in deadlock.
public final void join()  throws InterruptedException
public final void join(long milliseonds)  throws InterruptedException
public final void join(long milliseonds, int nanoseconds)  throws InterruptedException
package com.demo3;

public class ThreadNameDemo {
	public static void main(String[] args) throws InterruptedException {
		Thread t = new Thread(new TempThread());
		t.start();
		t.join(1000);
		for(int i=0; i<10;i++) {
			System.out.println("Main Thread : "+i);
		}
	} 
}
class TempThread implements Runnable{
	@Override
	public void run() {
		for(int i=0; i<10;i++) {
			try {
				Thread.sleep(300);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println("Child Thread : "+i);
		}
	}
}

Output :

Child Thread : 0
Child Thread : 1
Child Thread : 2
Main Thread : 0
Main Thread : 1
Main Thread : 2
Main Thread : 3
Main Thread : 4
Main Thread : 5
Main Thread : 6
Main Thread : 7
Main Thread : 8
Main Thread : 9
Child Thread : 3
Child Thread : 4
Child Thread : 5
Child Thread : 6
Child Thread : 7
Child Thread : 8
Child Thread : 9

Case 2 : Child Thread class join method on main method. (Child Thread waiting for main Thread to complete.)

public class ThreadNameDemo {
	public static void main(String[] args) throws InterruptedException {
		Thread t = new Thread(new TempThread(Thread.currentThread()));
		t.start();
		t.join();
		for(int i=0; i<5;i++) {
			System.out.println("Main Thread : "+i);
		}
	} 
}
class TempThread implements Runnable{
	public static Thread mainThread;
	TempThread(Thread t){
		mainThread = t;
	}
	@Override
	public void run() {
		try {
			mainThread.join();
			for(int i=0; i<5;i++) {
				Thread.sleep(300);
				System.out.println("Child Thread : "+i);
			}
		}catch(Exception e) {
			System.out.println("Exception has been caught : "+e);
		}
	}
}

Output :

Main Thread : 0
Main Thread : 1
Main Thread : 2
Main Thread : 3
Main Thread : 4
Child Thread : 0
Child Thread : 1
Child Thread : 2
Child Thread : 3
Child Thread : 4

Case 3: Main Thread and child thread both waiting for each other to complete (Deadlock)

public class ThreadNameDemo {
	public static void main(String[] args) throws InterruptedException {
		Thread t = new Thread(new TempThread(Thread.currentThread()));
		t.start();
		t.join();
		for(int i=0; i<5;i++) {
			System.out.println("Main Thread : "+i);
		}
	} 
}
class TempThread implements Runnable{
	public static Thread mainThread;
	TempThread(Thread t){
		mainThread = t;
	}
	@Override
	public void run() {
		try {
			mainThread.join();
			for(int i=0; i<5;i++) {
				System.out.println("Child Thread : "+i);
			}
		}catch(Exception e) {
			System.out.println("Exception has been caught : "+e);
		}
	}
}

or you see the below example as deadlock

public class ThreadNameDemo {
	
	public static void main(String[] args) throws InterruptedException {
		Thread.currentThread().join();
		System.out.println("Hello Thread");
	}
}

Sleep Method

  • If a thread don’t want to perform any operation for a particular amount of time then we should go for sleep method.
  • Every sleep method throws Interrupted Exception which is checked exception hence when ever we are using sleep method it is mandatory to handle Interrupted Exception.
public static native void sleep(long milliseconds) throws InterruptedException
public static void sleep(long milliseconds, int nanoseconds) throws InterruptedException

public class ThreadNameDemo {

public static void main(String[] args) throws InterruptedException {
    for(int i=0; i<5;i++) {
        Thread.sleep(500);
        System.out.println("Main Thread : "+i);
    }
}

How a Thread can Interrupt another Thread

A Thread can interrupt a sleeping thread or waiting thread by using interrupt method of thread class.

  • A Thread can interrupt a sleeping thread or waiting thread by using interrupt method of thread class.
  • If thread is not in sleeping state or waiting state then there is no impact of interrupt calling.
public void interrupt();
public class ThreadNameDemo {
	
	public static void main(String[] args) throws InterruptedException {
		Thread t = new Thread(new TempThread());
		t.start();
		t.interrupt();
		System.out.println("Thread stopped");
	} 
}
class TempThread implements Runnable{
	@Override
	public void run() {
		try {
			for(int i=0; i<5;i++) {
				System.out.println("Child Thread : "+i);
				Thread.sleep(1);
			}
		}catch(InterruptedException e) {
			System.out.println("InterruptedException has been caught : "+e);
		}
	}
}

Thread priorities

Point to remember in case of Thread priorities

  • Valid range of Java Thread priorities is from 1 to 10
  • 1 is the MIN priority (Thread.MIN_PRIORITY)
  • 10 is the MAX priority (Thread.MAX_PRIORITY)
  • 5 is the NORMAL priority (Thread.NORM_PRIORITY)
  • The default priority of main thread is 5 for all other threads the default priority will be inherited from parent thread to the child thread.
public final int getPriority();
public final void setPriority(int p); //allowed values from 1 to 10
public class ThreadNameDemo {
	public static void main(String[] args) {
		Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
		Thread t = new Thread(new TempThread());
		t.setPriority(Thread.MAX_PRIORITY);
		t.start();
		IntStream.rangeClosed(1,10).forEach(x -> System.out.println(Thread.currentThread().getName()+" "+x));
	} 
}
class TempThread implements Runnable{
	@Override
	public void run() {
		IntStream.rangeClosed(1,10).forEach(x -> System.out.println(Thread.currentThread().getName()+" "+x));
	}
}

Getting and setting name of thread

Thread.currentThread() method will fetch the currently executing Thread object and then you can set or get the name of the thread using setName(<new name>), getName() method respectively. Sample below.

import java.util.stream.IntStream;

public class ThreadNameDemo {
	public static void main(String[] args) {
		new Thread(new TempThread()).start();
		IntStream.rangeClosed(1,10).forEach(x -> System.out.println(Thread.currentThread().getName()+" "+x));
	} 
}
class TempThread implements Runnable{
	@Override
	public void run() {
		Thread.currentThread().setName("Child thread");
		IntStream.rangeClosed(1,10).forEach(x -> System.out.println(Thread.currentThread().getName()+" "+x));
	}
}

Defining a Thread in java using Runnable interface

Defining a thread :

We can define a thread in the following two ways :
a. By extending Thread class
b. By implementing runnable interface.

By implementing runnable interface.

Runnable interface is present in java.lang package and it contains one method called public void run() method.We can pass an object of a class which implements Runnable interface to the constructor a Thread class object and call the Thread class’s start method to start a new child thread, example below.

package com.demo2;

import java.util.stream.IntStream;

class MyRunnable implements Runnable{

	@Override
	public void run() {
		IntStream.range(1,10).forEach(x -> System.out.println("Child Thread : "+x));
	}
}

public class ThreadDemo {
	public static void main(String[] args) {
		Thread t = new Thread(new MyRunnable());
		t.start();
		IntStream.range(1,10).forEach(x -> System.out.println("Main Thread : "+x));
	}
}

Among the two ways to defining a thread, the implementing Runnable interface approach is suggest because the class implementing Runnable method still has a scope to extend another class but a class extending Thread class cannot support this functionality.

Defining a Thread in java by extending Thread class.

Defining a thread :

We can define a thread in the following two ways :
a. By extending Thread class
b. By implementing runnable interface.

By extending Thread class.

After extending a thread it is necessary to override the run method of the Thread class to define a job of the class.

package com.demo1;

import java.util.stream.IntStream;

public class MyThread extends Thread{ //Defining a Thread

	public void run() { //Job of a Thread
		IntStream.range(1,10).forEach(x -> System.out.println("Child Loop : "+x));
	}
}
class DemoRunningThread{
	public static void main(String[] args) { //Main Thread
		MyThread myThread = new MyThread(); //Thread instantiation
		myThread.start(); //Starting of a Thread
		IntStream.range(1,10).forEach(x -> System.out.println("Main Loop : "+x));
	}
}

Case 1 : Thread Scheduler

Thread Scheduler is a part of JVM, it is responsible to schedule threads If multiple threads are waiting to be executed then in which order they will be executed will be decided by Thread scheduler.The algorithm (SJF,FCFS,Round Robin) used by Thread scheduler differs from JVM to JVM. The output of the above program is not fixed it changes from JVM to JVM or from execution to execution, we cannot define which will be printed first.

Case 2 : Difference between thread.start() and thread.run()

In case of thread.start() a new thread will be created which will be responsible to execute out job but in case of thread.run() our run method will be executed like a normal method and a new thread will not be created.

Case 3 : Importance of Thread class start method

Thread class start method is responsible to register the thread with thread scheduler and all other mandatory activities. Hence without executing thread class start method there is not chance of starting a new thread in java due to this thread class start method is considered as heart of multi-threading.
Steps of Thread class’s start method
a. Register the thread with the Thread Schedular
b. Perform all other mandatory action.
c. Invoke the run method.

Case 4 : Overloaded run method

Overloading of run method is possible but thread.start() method will always call the empty parameter run() run method.Other overloaded run method with any number of arguments should be called explicitly.

Case 5 : Not overriding run method

We can have a class extend Thread class but not override the run method and still execute the program without any compilation or run time error because the Thread class has a run() method in its class with an empty implementation. It is highly recommended to override run method other wise it is better to not implement run method.

Case 6 : Overriding of start method.

In case when a class extends a thread class but also overrides the start() method then the Thread class’s start() method will not be called and a new thread will not be created. Just the contents of start() method of the child class which is extending the Thread parent class will be called.

Case 7 : super.start()

If super.start() method is called in the child class it can execute the start() method of the actual Thread class which will create the thread

package com.demo1;

import java.util.stream.IntStream;

public class MyThread extends Thread{ //Defining a Thread

	public void start() {
		super.start(); //Starting the Thread
		System.out.println("Start method");
	}
	
	public void run() { //Job of a Thread
		IntStream.range(1,10).forEach(x -> System.out.println("Child Loop : "+x));
	}
}
class DemoRunningThread{
	public static void main(String[] args) { //Main Thread
		MyThread myThread = new MyThread(); //Thread instantiation
		myThread.start(); //calling the start method of MyThread and not Thread class
		IntStream.range(1,10).forEach(x -> System.out.println("Main Loop : "+x));
	}
}

Case 8 : Thread Lifecycle

Note : Once you have started a thread using thread.start() method and again if you try to start the method we get exception IllegalThreadStateException

Introduction to Multithreading

Types of Multitasking

1.Processed based multitasking (Used by OS )
2.Thread based multitasking (Used by Programming Languages like Java)

What is Thread ?

  • A flow of execution is a Thread.
  • For every thread a separate individual job is present.

Use of multi threading in real world application

-To develop web server and application servers, were clients connect to application via web sever for each client a thread is created.

Where to use multi-threading concept?
-Where individual operations can be performed independently.

When compare with old languages implementing multithreading is much easier in java since java has rich multithreading API(Thread, Runnable,Group…..) and programmer is only required to perform 10% of the task is required by the programmer to perform 90% of the task is done by Java itself.

Thread Class constructors :

  1. Thread()
  2. Thread(String name)
  3. Thread(Runnable target)
  4. Thread(Runnable target, String name)
  5. Thread(ThreadGroup group, String name)
  6. Thread(ThreadGroup group, Runnable target)
  7. Thread(ThreadGroup group, Runnable target, String name)
  8. Thread(ThreadGroup group, Runnable target, String name, long stackSize)