Multithreading
Multithreading is a programming technique that allows a computer to run multiple
programs or tasks simultaneously. It's a way to divide up work into multiple threads that can
be processed in parallel by different CPU cores.
Fig. 1 Multithreading
Multithreading is a Java feature that allows concurrent execution of two or more
parts of a program for maximum utilization of CPU. Each part of such program is called a
thread. So, threads are light-weight processes within a process.
Lifecycle and States of a Thread in Java
A thread in Java can exist in any one of the following states at any given time. A thread
lies only in one of the shown states at any instant:
1. New State
2. Runnable State
3. Blocked State
4. Waiting State
5. Timed Waiting State
6. Terminated State
Fig. Life Cycle of Thread
Life Cycle of a Thread
There are multiple states of the thread in a lifecycle as mentioned below:
1. 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. When a thread lies in the new state, its
code is yet to be run and hasn’t started to execute.
2. Runnable State: A thread that is ready to run is moved to a runnable state. In this state,
a thread might actually be running or it might be ready to run at any instant of time. It is
the responsibility of the thread scheduler to give the thread, time to run. A multi-
threaded program allocates a fixed amount of time to each individual thread. Each and
every thread get a small amount of time to run. After running for a while, a thread
pauses and gives up the CPU so that other threads can run
3. Running: it means the process has given its time to the thread for its execution. After
generation of run() method the thread actually being with its execution. In this state
thread is actually being run and display the output
4. Blocked: The thread will be in blocked state when it is trying to acquire a lock but
currently the lock is acquired by the other thread. The thread will move from the
blocked state to runnable state when it acquires the lock.
4. Waiting state: The thread will be in waiting state when it calls wait() method or join()
method. It will move to the runnable state when other thread will notify or that thread
will be terminated.
5. Timed Waiting: A thread lies in a timed waiting state when it calls a method with a
time-out parameter. A thread lies in this state until the timeout is completed or until a
notification is received. For example, when a thread calls sleep or a conditional wait, it
is moved to a timed waiting state.
6. 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.
Because there occurred some unusual erroneous event, like a segmentation fault or
an unhandled exception.
Implementation of Thread States
In Java, one can get the current state of a thread using the Thread.getState() method.
The java.lang.Thread.State class of Java provides the constants ENUM to represent the state
of a thread. These constants are:
1. public static final Thread.State NEW
It represents the first state of a thread that is the NEW state.
1. public static final Thread.State RUNNABLE
It represents the runnable state.It means a thread is waiting in the queue to run.
1. public static final Thread.State BLOCKED
It represents the blocked state. In this state, the thread is waiting to acquire a lock.
1. public static final Thread.State WAITING
It represents the waiting state. A thread will go to this state when it invokes the Object.wait()
method, or Thread.join() method with no timeout. A thread in the waiting state is waiting for
another thread to complete its task.
1. public static final Thread.State TIMED_WAITING
It represents the timed waiting state. The main difference between waiting and timed waiting
is the time constraint. Waiting has no time constraint, whereas timed waiting has the time
constraint. A thread invoking the following method reaches the timed waiting state.
o sleep
o join with timeout
o wait with timeout
o parkUntil
o parkNanos
public static final Thread.State TERMINATED
It represents the final state of a thread that is terminated or dead. A terminated thread means it
has completed its execution.
Thread Creation
1. We can extend the thread class, itself.
2. We can implement the runnable statement
Constructors of Thread Class
Constructor Action Performed
Thread() Allocates a new Thread object.
Thread(Runnable target) Allocates a new Thread object.
Thread(Runnable target, String
Allocates a new Thread object.
name)
Thread(String name) Allocates a new Thread object.
Thread(ThreadGroup group,
Allocates a new Thread object.
Runnable target)
Thread Class Methods
Methods Action Performed
Returns an estimate of the number of active
activeCount() threads in the current thread’s thread group and
its subgroups
Determines if the currently running thread has
checkAccess()
permission to modify this thread
Throws CloneNotSupportedException as a
clone()
Thread can not be meaningfully cloned
Returns a reference to the currently executing
currentThread()
thread object
Methods Action Performed
Prints a stack trace of the current thread to the
dumpStack()
standard error stream
Copies into the specified array every active
enumerate(Thread[] tarray) thread in the current thread’s thread group and
its subgroups
getAllStackTraces() Returns a map of stack traces for all live threads
getContextClassLoader() Returns the context ClassLoader for this Thread
Returns the default handler invoked when a
getDefaultUncaughtExceptionHa
thread abruptly terminates due to an uncaught
ndler()
exception
getId() Returns the identifier of this Thread
getName() Returns this thread’s name
getPriority() Returns this thread’s priority
Returns an array of stack trace elements
getStackTrace()
representing the stack dump of this thread
getState() Returns the state of this thread
Returns the thread group to which this thread
getThreadGroup()
belongs
Methods Action Performed
Returns the handler invoked when this thread
getUncaughtExceptionHandler() abruptly terminates due to an uncaught
exception
Returns true if and only if the current thread
holdsLock(Object obj)
holds the monitor lock on the specified object
interrupt() Interrupts this thread
Tests whether the current thread has been
interrupted()
interrupted
isAlive() Tests if this thread is alive
isDaemon() Tests if this thread is a daemon thread
isInterrupted() Tests whether this thread has been interrupted
join() Waits for this thread to die
Waits at most millis milliseconds for this thread
join(long millis)
to die
If this thread was constructed using a separate
Runnable run object, then that Runnable
run()
object’s run method is called; otherwise, this
method does nothing and returns
setContextClassLoader(ClassLoa
Sets the context ClassLoader for this Thread
der cl)
Methods Action Performed
Marks this thread as either a daemon thread or
setDaemon(boolean on)
a user thread
setDefaultUncaughtExceptionHa Set the default handler invoked when a thread
ndler( abruptly terminates due to an uncaught
Thread.UncaughtExceptionHandl exception, and no other handler has been
er eh) defined for that thread
Changes the name of this thread to be equal to
setName(String name)
the argument name.
setUncaughtExceptionHandler( Set the handler invoked when this thread
Thread.UncaughtExceptionHandl abruptly terminates due to an uncaught
er eh) exception
setPriority(int newPriority) Changes the priority of this thread
Causes the currently executing thread to sleep
(temporarily cease execution) for the specified
sleep(long millis)
number of milliseconds, subject to the precision
and accuracy of system timers and schedulers
Causes this thread to begin execution; the Java
start() Virtual Machine calls the run method of this
thread
Returns a string representation of this thread,
toString() including the thread’s name, priority, and thread
group
A hint to the scheduler that the current thread is
yield()
willing to yield its current use of a processor
Inter-thread Communication in Java
Inter-thread communication in Java is a mechanism in which a thread is paused
running in its critical section and another thread is allowed to enter (or lock) in the
same critical section to be executed.
What is Polling, and what are the problems with it?
The process of testing a condition repeatedly till it becomes true is known as
polling. Polling is usually implemented with the help of loops to check whether a
particular condition is true or not. If it is true, a certain action is taken. This wastes
many CPU cycles and makes the implementation inefficient.
For example, in a classic queuing problem where one thread is producing data, and
the other is consuming it.
How Java Multi-Threading tackles this problem?
To avoid polling, Java uses three methods, namely, wait(), notify(), and
notifyAll(). All these methods belong to object class as final so that all classes
have them. They must be used within a synchronized block only.
wait(): It tells the calling thread to give up the lock and go to sleep until some
other thread enters the same monitor and calls notify().
notify(): It wakes up one single thread called wait() on the same object. It
should be noted that calling notify() does not give up a lock on a resource.
notifyAll(): It wakes up all the threads called wait() on the same object.
Java Thread Priority in Multithreading
Priorities in Threads in Java is a concept where each thread has a priority in
layman’s language one can say every object has priority here which is represented
by numbers ranging from 1 to 10, and the constant defined can help to implement
which are mentioned below.
Constant Description
public static int Sets the default priority for the Thread. (Priority:
NORM_PRIORITY 5)
public static int Sets the Minimum Priority for the Thread.
MIN_PRIORITY (Priority: 1)
public static int Sets the Maximum Priority for the Thread.
MAX_PRIORITY (Priority: 10)
Example:
import java.lang.*;
class Thread1 extends Thread {
// run() method for the thread that is called
// as soon as start() is invoked for thread in main()
public void run()
{
System.out.println(Thread.currentThread().getName()
+ " is running with priority "
+ Thread.currentThread().getPriority());
}
// Main driver method
public static void main(String[] args)
{
// Creating random threads
// with the help of above class
Thread1 t1 = new Thread1();
Thread1 t2 = new Thread1();
Thread1 t3 = new Thread1();
// Display the priority of above threads
// using getPriority() method
System.out.println("t1 thread priority: " + t1.getPriority());
System.out.println("t2 thread priority: " + t2.getPriority());
System.out.println("t3 thread priority: " + t3.getPriority());
// Setting priorities of above threads by
// passing integer arguments
t1.setPriority(2);
t2.setPriority(5);
t3.setPriority(8);
// Error will be thrown in this case
// t3.setPriority(21);
// Last Execution as the Priority is low
System.out.println("t1 thread priority: " + t1.getPriority());
// Will be executed before t1 and after t3
System.out.println("t2 thread priority: " + t2.getPriority());
// First Execution as the Priority is High
System.out.println("t3 thread priority: " + t3.getPriority());
// Now Let us Demonstrate how it will work
// According to it's Priority
t1.start();
t2.start();
t3.start();
// Thread - 0, 1 , 2 signify 1 , 2 , 3
// respectively
}
}
Synchronization in Java
In Multithreading, Synchronization is crucial for ensuring that multiple threads
operate safely on shared resources. Without Synchronization, data inconsistency or
corruption can occur when multiple threads try to access and modify shared variables
simultaneously. In Java, it is a mechanism that ensures that only one thread can access a
resource at any given time. This process helps prevent issues such as data inconsistency
and race conditions when multiple threads interact with shared resources.
Example :
// Java Program to demonstrate synchronization in Java
class Counter {
private int c = 0; // Shared variable
// Synchronized method to increment counter
public synchronized void inc() {
c++;
}
// Synchronized method to get counter value
public synchronized int get() {
return c;
}
}
public class Geeks {
public static void main(String[] args) {
Counter cnt = new Counter(); // Shared resource
// Thread 1 to increment counter
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
cnt.inc();
}
});
// Thread 2 to increment counter
Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
cnt.inc();
}
});
// Start both threads
t1.start();
t2.start();
// Wait for threads to finish
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
// Print final counter value
System.out.println("Counter: " + cnt.get());
}
}