Contents

Multithreading in Java

Theory

Threads can be created by using two mechanisms:

  • Extending the Thread class
  • Implementing the Runnable Interface

Thread creation by extending the Thread class

We create a class that extends the java.lang.Thread class. This class overrides the run() method available in the Thread class. A thread begins its life 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.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// Java code for thread creation by extending
// the Thread class
class MultithreadingDemo extends Thread {
	public void run() {
		try {
			// Displaying the thread that is running
			System.out.println("Thread " + Thread.currentThread().getId() + " is running");
		} catch (Exception e) {
			// Throwing an exception
			System.out.println("Exception is caught");
		}
	}
}

// Main Class
public class Multithread {
	public static void main(String[] args) {
		int n = 8; // Number of threads
		for (int i = 0; i < n; i++) {
			MultithreadingDemo object = new MultithreadingDemo();
			object.start();
		}
	}
}

Thread creation by implementing the Runnable Interface

We create a new class which implements java.lang.Runnable interface and override run() method. Then we instantiate a Thread object and call start() method on this object.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// Java code for thread creation by implementing
// the Runnable Interface
class MultithreadingDemo implements Runnable {
	public void run() {
		try {
			// Displaying the thread that is running
			System.out.println("Thread " + Thread.currentThread().getId() + " is running");
		} catch (Exception e) {
			// Throwing an exception
			System.out.println("Exception is caught");
		}
	}
}

// Main Class
class Multithread {
	public static void main(String[] args) {
		int n = 8; // Number of threads
		for (int i = 0; i < n; i++) {
			Thread object = new Thread(new MultithreadingDemo());
			object.start();
		}
	}
}

Thread Class vs Runnable Interface
  • If we extend the Thread class, 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.
  • We can achieve basic functionality of a thread by extending Thread class because it provides some inbuilt methods like yield(), interrupt() etc. that are not available in Runnable interface.
  • Using runnable will give you an object that can be shared amongst multiple threads.

Life Cycle of a thread

New Thread: When a new thread is created, it is in the new state. The thread has not yet started to run when the thread is in this state.

Runnable State: A thread that is ready to run is moved to a runnable state. The thread is currently excecuting the run() method.

A multi-threaded program allocates a fixed amount of time to each individual thread. Each and every thread runs for a short while and then pauses and relinquishes the CPU to another thread so that other threads can get a chance to run. When this happens, all such threads that are ready to run, waiting for the CPU and the currently running thread lie in a runnable state.

Blocked/Waiting state: When a thread is temporarily inactive, then it’s in one of the following states:

  • Blocked: Suspended because some operation is blocked.
  • Waiting: Waiting because of some operation.

Timed Waiting: A thread lies in a timed waiting state when it calls a method with a time-out parameter, like Thread.sleep(). A thread lies in this state until the timeout is completed or until a notification is received.

Terminated State: A thread terminates because of either of the following reasons:

  • Because it exits normally. This happens when the code of the thread has been entirely executed by the program, like the run() method.
  • Because there occurred some unusual erroneous event, like segmentation fault or an unhandled exception.

Main Thread

In java, a java program is a JVM process, When a Java program starts up, one thread in JVM process begins running immediately. This is usually called the main thread of our program because it is the one that is executed when our program begins, this main thread will excecute main() method.

There are certain properties associated with the main thread which are as follows:

  • It is the thread from which other “child” threads will be spawned.
  • Often, it must be the last thread to finish execution because it performs various shutdown actions
How to control Main thread

The main thread is created automatically when our program is started. To control it we must obtain a reference to it. This can be done by calling the method currentThread() which is present in Thread class. This method returns a reference to the thread on which it is called. The default priority of Main thread is 5 and for all remaining user threads priority will be inherited from parent to child.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
// Java program to control the Main Thread

// Importing required classes
import java.io.*;
import java.util.*;

// Class 1
// Main class extending thread class
public class Test extends Thread {

	// Main driver method
	public static void main(String[] args)
	{

		// Getting reference to Main thread
		Thread t = Thread.currentThread();

		// Getting name of Main thread
		System.out.println("Current thread: "
						+ t.getName());

		// Changing the name of Main thread
		t.setName("Geeks");
		System.out.println("After name change: "
						+ t.getName());

		// Getting priority of Main thread
		System.out.println("Main thread priority: "
						+ t.getPriority());

		// Setting priority of Main thread to MAX(10)
		t.setPriority(MAX_PRIORITY);

		// Print and display the main thread priority
		System.out.println("Main thread new priority: "
						+ t.getPriority());

		for (int i = 0; i < 5; i++) {
			System.out.println("Main thread");
		}

		// Main thread creating a child thread
		Thread ct = new Thread() {
			// run() method of a thread
			public void run()
			{

				for (int i = 0; i < 5; i++) {
					System.out.println("Child thread");
				}
			}
		};

		// Getting priority of child thread
		// which will be inherited from Main thread
		// as it is created by Main thread
		System.out.println("Child thread priority: "
						+ ct.getPriority());

		// Setting priority of Main thread to MIN(1)
		ct.setPriority(MIN_PRIORITY);

		System.out.println("Child thread new priority: "
						+ ct.getPriority());

		// Starting child thread
		ct.start();
	}
}

// Class 2
// Helper class extending Thread class
// Child Thread class
class ChildThread extends Thread {

	@Override public void run()
	{

		for (int i = 0; i < 5; i++) {

			// Print statement whenever child thread is
			// called
			System.out.println("Child thread");
		}
	}
}

Thread Pools

What is ThreadPool in Java

A thread pool reuses previously created threads to execute current tasks and offers a solution to the problem of thread cycle overhead and resource thrashing. Since the thread is already existing when the request arrives, the delay introduced by thread creation is eliminated, making the application more responsive.

  • Java provides the Executor framework which is centered around the Executor interface, its sub-interface –ExecutorService and the class-ThreadPoolExecutor, which implements both of these interfaces. By using the executor, one only has to implement the Runnable objects and send them to the executor to execute.
  • They allow you to take advantage of threading, but focus on the tasks that you want the thread to perform, instead of thread mechanics.
  • To use thread pools, we first create an object of ExecutorService and pass a set of tasks to it. ThreadPoolExecutor class allows to set the core and maximum pool size. The runnables that are run by a particular thread are executed sequentially.

Steps to use thread pool

  1. Create a task(Runnable Object) to execute
  2. Create Executor Pool using Executors
  3. Pass tasks to Executor Pool
  4. Shutdown the Executor Pool
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
// Java program to illustrate
// ThreadPool
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

// Task class to be executed (Step 1)
class Task implements Runnable
{
	private String name;
	
	public Task(String s)
	{
		name = s;
	}
	
	// Prints task name and sleeps for 1s
	// This Whole process is repeated 5 times
	public void run()
	{
		try
		{
			for (int i = 0; i<=5; i++)
			{
				if (i==0)
				{
					Date d = new Date();
					SimpleDateFormat ft = new SimpleDateFormat("hh:mm:ss");
					System.out.println("Initialization Time for"
							+ " task name - "+ name +" = " +ft.format(d));
					//prints the initialization time for every task
				}
				else
				{
					Date d = new Date();
					SimpleDateFormat ft = new SimpleDateFormat("hh:mm:ss");
					System.out.println("Executing Time for task name - "+
							name +" = " +ft.format(d));
					// prints the execution time for every task
				}
				Thread.sleep(1000);
			}
			System.out.println(name+" complete");
		}
		
		catch(InterruptedException e)
		{
			e.printStackTrace();
		}
	}
}
public class Test
{
	// Maximum number of threads in thread pool
	static final int MAX_T = 3;			

	public static void main(String[] args)
	{
		// creates five tasks
		Runnable r1 = new Task("task 1");
		Runnable r2 = new Task("task 2");
		Runnable r3 = new Task("task 3");
		Runnable r4 = new Task("task 4");
		Runnable r5 = new Task("task 5");	
		
		// creates a thread pool with MAX_T no. of
		// threads as the fixed pool size(Step 2)
		ExecutorService pool = Executors.newFixedThreadPool(MAX_T);
		
		// passes the Task objects to the pool to execute (Step 3)
		pool.execute(r1);
		pool.execute(r2);
		pool.execute(r3);
		pool.execute(r4);
		pool.execute(r5);
		
		// pool shutdown ( Step 4)
		pool.shutdown();	
	}
}