Multithreading in Java

11 min readJun 7, 2021


If we can execute several tasks simultaneously we call that concept multitasking. There are two types of multitasking.

  1. Process Based Multitasking

2. Thread Based Multitasking

Process Based Multitasking

Process based multitasking is the execution of multiple tasks at the same time, each of which is a separate independent program (process).

Example : We can listen to audio music from the same system while typing a java application in the editor. We can also download a file from the internet at the same time. All of these duties will be completed at the same time and in a separate order. As a result, multitasking is based on processes.

At the operating system level, Process based multitasking is very efficient.

Thread Based Multitasking

  • Thread based multitasking refers to the execution of many tasks at the same time, where each task is a different independent part of the same program, and each independent part is referred to as a thread.
  • A thread is the unit of execution within a process. A process can have anywhere from just one thread to many threads.
  • Threads use a shared memory region rather than allocating a distinct memory region, which saves memory and allows for faster context switching across threads than processes
  • It’s best used at the programming level.
  • As java provides inbuilt support for multithreading with rich API it is very convenient to develop multithreaded applications in java


  • Multithreading in Java is a process of executing multiple threads simultaneously
  • A thread is the smallest unit of processing and is a lightweight sub process. It has a distinct execution route.
  • A thread is executed within the process, as illustrated in the diagram above. Between the threads, there is context switching.
  • Within the OS, there can be several processes, and each process can have many threads.
  • Multithreading’s main goal is to maximize CPU utilization by allowing two or more sections of a program to run at the same time.
  • A multithreaded program contains two or more parts that can run concurrently. Each such part of a program called thread.

Advantages and Applications of Multithreading

  • The basic goal of multitasking, whether it’s process-based or thread-based, is to minimize the system’s response time and improve its performance.
  • Because threads are independent and many operations can be performed at the same time, it does not cause the user to be blocked.
  • It saves time by allowing to do multiple operations at once.
  • Because threads are self-contained, an exception in one thread has no impact on other threads.
  • The main important application areas of multithreading are:

— To develop multimedia graphics

— To develop animations

— To develop video games.

— To develop web servers and application servers, etc

Defining a Thread

The Thread class, its methods, and its companion interface, Runnable, are the foundations of Java’s multithreading system. We can define a thread in the following two ways:

  1. By extending Thread class
  2. By implementing Runnable interface

The Thread class contains constructors and methods for creating and operating on threads. Thread is a subclass of Object that implements the Runnable interface.

Thread Scheduler

  • It is a component of the JVM that is in charge of thread scheduling. That is, if numerous threads are ready to be executed, the thread scheduler determines the order in which they will be processed.
  • We can’t expect the thread scheduler to follow an exact methodology. It differs from one JVM to the next. As a result, we can’t assume exact thread execution order or output.
  • As a result, there is no guarantee of exact output when it comes to multithreading.
  • The thread scheduler schedules the threads mostly using preemptive or time slicing scheduling.
  • When using preemptive scheduling, the highest priority task runs until it enters the waiting or dead states, or until a higher priority job is created.
  • In time slicing, a job runs for a predetermined amount of time before returning to the pool of ready tasks.

Thread class start() method

Is responsible to register the thread with thread scheduler and all other mandatory activities. There is no way to start a new thread in Java without first performing the thread class start method. It calls the run() method.

The Thread class start function is considered the heart of multithreading because of this. A thread’s life cycle has numerous stages, and threads exist in a variety of states.

  • It is possible for a thread to be active.
  • As soon as it receives CPU time, it will be ready to run.
  • The activity of a running thread can be temporarily halted by suspending it.
  • A thread that has been suspended can then be resumed, allowing it to continue where it left off.
  • When a thread is waiting for a resource, it can become blocked.
  • A thread can be terminated at any point, halting its operation immediately. A thread cannot be restarted once it has been terminated.

Thread Life Cycle

Thread Life Cycle

Thread States

  • New (Born) State: If create a new instance of Thread, it will be in a new state.class, but before the start() method is called. When a thread instance is created.It will be in the “New” state after it is created.
  • Runnable (Ready) State: The thread is in a runnable state after calling the start() method, but it has not been picked as the running thread by the thread scheduler. The thread is in the “Runnable” state when it is started.
  • Running State: The thread is in running state if the thread scheduler has selected it. When the thread is running, it is called “Running” state
  • Waiting (Blocked) State: This is the state when the thread is still alive, but is currently not eligible to run. When the thread is put on hold or it is waiting for the other thread to complete, then that state will be known as “waiting” state.
  • Terminated (Dead) State: A thread is in terminated or dead state when its run() method exits. When the thread is dead, it will be known as “terminated” state

The Main Thread

When a Java application starts, one thread is instantly active. This is commonly referred to as the main thread of program because it is the first one to run when application starts.

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.

Although program’s main thread is established automatically when it starts, can control it with a Thread object. To do so, must first gain a reference to it by invoking the public static member of Thread currentThread( ). Here’s how it looks in its most basic form: currentThread static Thread ( )

This method returns a reference to the thread in which it is called. Once have a reference to the main thread, can control it just like any other thread.

sleep() method

The sleep( ) function suspends execution of the thread from which it is called for the provided number of milliseconds.

  • Its general form is shown here:

static void sleep(long milliseconds) throws InterruptedException

In milliseconds, the number of milliseconds to suspend is provided. An InterruptedException may be thrown by this procedure.

  • A second form of the sleep( ) method is given next, which allows to select the period in milliseconds and nanoseconds:

static void sleep(long milliseconds, int nanoseconds) throws InterruptedException

setName() and getName() methods

  • In Java, each thread has a name. It could be a JVM-generated default name or a user-defined name.
  • Thread-0, Thread-1, and so on will be the default names.
  • setName() can be used to specifically set a thread’s name.
  • The name of a thread can be obtained by executing getName ( ).
  • These methods are Thread class members and are declared as follows:

— public final void setName(String threadName);

— public final String getName( );

Creating a Thread by implementing the Runnable Interface

  • Implement a run() method provided by a Runnable interface. This method provides an entry point for the thread and will put complete business logic inside this method. Following is a simple syntax of the run() method − public void run( );
  • As a second step, Instantiate a Thread object using the following constructor − Thread(Runnable threadObj, String threadName) Or Thread(Runnable threadObj) Where, threadObj is an instance of a class that implements the Runnable interface and threadName is the name given to the new thread.
  • Once a Thread object is created, start it by calling start() method, which executes a call to run( ) method. Following is a simple syntax of start() method − void start();

Creating a Thread by extending the Thread Class

  • To create a thread, first make a new class that extends Thread, and then make an instance of it.
  • The extending class must override the run( ) function, which serves as the new thread’s entry point.
  • Following is a simple syntax of run() method − public void run( );
  • It must also call start( ) to begin execution of the new thread.
  • Following is a simple syntax of start() method − void start( );

isAlive( ) method

  • We can use the isAlive( ) method on a thread to see if it has ended.
  • Thread defines this technique, and its general form is as follows:

final boolean isAlive( )

  • The isAlive( ) function returns true if the thread that it is called on is still running. Otherwise, it returns false.

join() method

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 thread t2 then t1 has to call t2.join(); If t1 executes t2.join() then immediately t1 will be entered into waiting state until t2 completes. Once t2 completes then t1 can continue its execution.

join method has following two forms:

— public final void join() throws InterruptedException;

— public final void join(long ms) throws InterruptedException ;

— public final void join(long ms, int ns) throws InterruptedException;

interrupt() method

  • A thread can use the interrupt() function of the Thread class to wake up a sleeping or waiting thread.
  • It’s general form is : public void interrupt()
  • If the thread is neither sleeping or waiting, the interrupt() method behaves normally and does not interrupt the thread, but it does change the interrupt flag to true.

Thread Priorities

  • Every Java thread has a priority in Java. It could be a JVM-generated default priority or a programmer-defined priority.
  • Thread priorities can be between 1 and 10, with 1 being the lowest and 10 being the highest.
  • To indicate some standard priority, the Thread class defines the following constants:

— Thread.MIN_PRIORITY = 1

— Thread.NORM_PRIORITY = 5

— Thread.MAX_PRIORITY =10

  • Threads with a higher priority are more vital to a program and should be given priority over lower-priority threads when allocating processor time.
  • The thread scheduler, in most circumstances, arranges the threads according to their priority (known as preemptive scheduling).

setPriority() and getPriority() methods

  • Thread class defines the following methods to get and set priority of a thread:

— public final int getPriority()

— public final void setPriority(int p)

  • Here, p specifies the new priority setting for the calling thread. The valid range of p is within the range MIN_PRIORITY and MAX_PRIORITY.
  • We can obtain the current priority setting by calling the getPriority( ) method.
  • To set a thread’s priority, use the setPriority( ) method.
  • The default priority for main thread is 5 and for others default priority for other threads will be inherited from its parent. •
  • This method throws IllegalArgumentException if value of parameter level goes beyond minimum(1) and maximum(10) limit.

yield() method

  • yield() causes the current thread to pause in order to make room for waiting threads with the same priority.
  • If no waiting threads exist or if all waiting threads have a low priority, the current thread can continue to run.
  • If numerous threads with the same priority are waiting, we have no way of knowing which one will receive the chance because it is determined by the thread scheduler.
  • The general form is: public static void yield()
  • If we comment out line ‘Thread.yield();’ in the above program, both threads will be executed at the same time, and we won’t be able to predict which thread will complete first.
  • If we don’t comment line’Thread.yield(); ‘, the main thread will have a higher chance of completing first.


Synchronization in Java refers to the ability to govern different threads’ access to a shared resource.When two or more threads need access to a shared resource, they need a mechanism to guarantee that only one thread is using it at a time. Synchronization is the method by which this is accomplished.

When we only want one thread to access a shared resource, Java Synchronization is a better solution. Synchronization is primarily used to:

  • Avoid thread interference;
  • Avoid consistency issues.

Synchronization is based on a lock or monitor, which is an internal entity. A lock is associated with every object. By convention, a thread that requires consistent access to an object’s fields must first acquire the object’s lock, then release the lock after it’s finished.

synchronized keyword

  • The synchronized modification only applies to methods and blocks, not classes or variables.
  • If many threads are attempting to operate on the same Java object, there is a risk of data inconsistency; to avoid this, we should use the synchronized keyword.
  • If a method or block is declared synchronized, only one thread at a time is allowed to execute that method or block on the supplied object, preventing data inconsistency.
  • The main benefit of the synchronized keyword is that it allows us to overcome data inconsistency issues, but the main disadvantage is that it increases thread waiting time and causes performance issues.
  • As a result, if there is no specified requirement, the synchronized keyword is not advised.


  • Every object in java has synchronized area and non-synchronized area.
  • The synchronized area can be accessed by only one thread a time, but non synchronized area can be accessed by any number of threads at a time.
  • The code where we do update actions like as add, delete, and update should be included in the synchronized section. That is, the status of the object changes.
  • The non-synchronized area includes actions like read that do not modify the state of an object.

Synchronized Block

  • The synchronized block can be used to perform synchronization on any of the method’s resources.
  • If method has 50 lines of code and just want to synchronize 5 of them, can use a synchronized block.
  • It will work the same as the synchronized method if place all of the method’s codes in the synchronized block.

— Syntax

synchronized (object reference expression) {

//code block


wait() method:

  • This function forces the current thread to release the lock and wait until another thread calls the notify() or notifyAll() methods on this object, or until a certain period of time has passed.
  • That is, when we call wait(), the current thread is forced to wait until another thread on the same object calls notify() or notifyAll().
  • The current thread must own this object’s monitor, so it must be called from the synchronized method only otherwise it will throw exception.
  • It has following three overloaded forms:

public final void wait() throws;

InterruptedException public final native wait(long ms) throwsInterruptedException ;

public final wait(long ms, int ns) throws InterruptedException;

  • The InterruptedException, which is a checked exception, is thrown by every wait() procedure.
  • As a result, whenever we use wait(), we must either use the try catch or throws keyword to handle the InterruptedException. Otherwise, a build time error will occur.

notify() and notifyAll() methods

  • notify() creates a single thread that is waiting on the monitor of this object.
  • If this object has any waiting threads, one of them is picked to be awakened.
  • The decision is arbitrary and made at the implementation’s discretion.
  • notifyAll() wakes up all threads waiting on the monitor of this object.
  • The forms of these methods:

public final void notify()

public final native void notifyAll()