Multi Threading in Java : Free Java Tutorials and Online Training

Multitasking – The objective of multitasking is to execute multiple tasks simultaneously to reduce CPU response time and make program execution faster and improve overall system performance. In Java we have multi processing and multi threading.

It can be achieved in two ways:

1) Process-based Multitasking (multi-processing)

In multi-processing, each task that is being concurrently executed is a separate independent process. It is generally beneficial at operating system level.

For example, modern computers have many processor chips. They have multiple cores (aka multicore processors), meaning they are actually composed of several different processors.

In this case, the word multiprocessing just means the work that our computer does is divided among several different processors and each processor works concurrently on a separate independent process.

2) Thread-based Multitasking (Multi threading)

In multi threading, each task that is being concurrently executed is a separate part of the same program. It is generally beneficial at programmatic level.

Web server is the best example to understand multi-threading. Every time a request comes in, it gets assigned to a completely new thread. That thread will then take care of all processing required for that particular request.

In this case, all threads work simultaneously to handle customer requests and they make web server execution faster. Note that all threads are essentially the part of a same program to handle customer request and run web server.


Multi threading in Java

We can utilize this concept of multi-threading at programmatic level and make our programs execute faster. Developing multi-threaded applications in Java is very easy because Java provides inbuilt support for multi threading with rich API.

Threads can be created in two ways in Java:

  1. Extending the Thread class
  2. Implementing the Runnable Interface

Let’s understand this with an example.

Method 1: Extending Thread Class

We create our own class that extends the java.lang.Thread class. This class overrides the run() method available in the Thread class. A thread starts executing inside run() method. We create an object of our new class and call start() method to start the execution of a thread. Start() invokes the run() method on the Thread object.

// We create our own class named MultiThread that extends Thread class
class MultiThread extends Thread
{
	// We define two characteristics of any thread, its name and id
	private int thread_id;
	private String thread_name;
	
	// Constructor to initialize new thread object
	MultiThread(String name, int id)
	{
		this.thread_id=id;
		this.thread_name=name;
	}
	
	// Overridden run method
	public void run()
	{
		try 
		{
			// Printing that thread execution starts now
System.out.println("Thread named " + this.thread_name + " with id  = " + this.thread_id + " is running");
			try
			{
Thread.sleep(2000); // putting this thread in sleep mode  // for 2 seconds (2000 mili-seconds)
			}
catch (InterruptedException exc) // handling possible Interrupted // Exception
			{
				System.out.println("Thread has been interrupted.");
			}
		}
		catch (Exception exc) // handling possible Exception
		{
			System.out.println("EXCEPTION CAUGHT..!!!");
		}
		// Printing that thread execution ends now
System.out.println("Thread named " + this.thread_name + " with id = " + this.thread_id + " is now exiting");
	}
}

Here is the code for our own class named MultiThread that extends Thread class. This is one way of creating threads in Java. In this code, each thread has been given a name and an id. Each thread starts its execution inside run() method, sleeps for a time interval of 2 seconds and then stops its execution.

Following is the code for our main function from which we will create objects of threads and call their start() function.

// Main class
public class Demo
{
	public static void main(String args[])
	{
// Creating two thread objects of our class named MultiThread and 
// starting both the threads concurrently.
		Thread thread1 = new MultiThread("Multi-Thread-1",1);
		thread1.start();
		
// We are explicitly assigning name and id to each thread while creating // them.
		Thread thread2 = new MultiThread("Multi-Thread-2",2);
		thread2.start();
	}
}

Output – 

Thread named Multi-Thread-2 with id = 2 is running
Thread named Multi-Thread-1 with id = 1 is running
Thread named Multi-Thread-1 with id = 1 is now exiting
Thread named Multi-Thread-2 with id = 2 is now exiting

We can see from the output that both threads are running concurrently. There is no specific order of execution of threads. They are running simultaneously. This can be seen from the output: Even though Thread1 started running first, it was Thread2 whose execution ended first. The order of execution is never fixed. We might get different order when we run it again. Note that after first two statements are printed, there will be 2 seconds pause and after that the other two statements will be printed as we have put each thread to sleep for 2 seconds.


Method 2: Implementing Runnable Interface

We just need to implement Runnable interface instead of extending Thread class.

Main class should be modified in the following way.

// Main class
public class Demo
{
	public static void main(String args[])
	{
// Creating two thread objects of our class named MultiThread and 
// starting both the threads concurrently.
		Thread thread1 = new Thread(new MultiThread("Multi-Thread-1",1));
		thread1.start();
		
// We are explicitly assigning name and id to each thread while creating // them.
		Thread thread2 = new Thread(new MultiThread("Multi-Thread-2",2));
		thread2.start();
	}
}

Our MultiThread class which implements Runnable Interface remains same.

// We create our own class named MultiThread that extends Thread class
class MultiThread implements Runnable
{
	// We define two characteristics of any thread, its name and id
	private int thread_id;
	private String thread_name;
	
	// Constructor to initialize new thread object
	MultiThread(String name, int id)
	{
		this.thread_id=id;
		this.thread_name=name;
	}
	
	// Overridden run method
	public void run()
	{
		try 
		{
			// Printing that thread execution starts now
System.out.println("Thread named " + this.thread_name + " with id  = " + this.thread_id + " is running");
			try
			{
Thread.sleep(2000); // putting this thread in sleep mode  // for 2 seconds (2000 mili-seconds)
			}
catch (InterruptedException exc) // handling possible Interrupted // Exception
			{
				System.out.println("Thread has been interrupted.");
			}
		}
		catch (Exception exc) // handling possible Exception
		{
			System.out.println("EXCEPTION CAUGHT..!!!");
		}
		// Printing that thread execution ends now
System.out.println("Thread named " + this.thread_name + " with id = " + this.thread_id + " is now exiting");
	}
}

Output- 

Thread named Multi-Thread-1 with id = 1 is running
Thread named Multi-Thread-2 with id = 2 is running
Thread named Multi-Thread-1 with id = 1 is now exiting
Thread named Multi-Thread-2 with id = 2 is now exiting

Thread Class vs Runnable Interface

If we extend the Thread class to create our custom thread class, then our class cannot extend any other class because Java doesn’t support multiple inheritance. But, if we implement the Runnable interface, our class can still extend other base classes. This is one big advantage of implementing Runnable interface instead of extending Thread class.


Hope you enjoyed this article and clear all concepts about multi threading.