Multithreading
• A multi-threaded program contains two or more parts that can run
concurrently and each part can handle a different task at the same time
making optimal use of the available resources.
• By definition, multitasking is when multiple processes share common
processing resources such as a CPU. Multi-threading extends the idea of
multitasking into applications where you can subdivide specific operations
within a single application into individual threads. Each of the threads can
run in parallel. The OS divides processing time not only among different
applications, but also among each thread within an application.
• Multi-threading enables you to write in a way where multiple activities
can proceed concurrently in the same program. To achieve the
multithreading (or, write multithreaded code), you need java.lang.Thread
class.
Life Cycle of a Thread in Java
Multithreading
• A thread goes through various stages in its life cycle. For example, a
thread is born, started, runs, and then dies.
• New − A new thread begins its life cycle in the new state. It remains in this state until the
program starts the thread. It is also referred to as a born thread.
• Runnable − After a newly born thread is started, the thread becomes runnable. A thread in
this state is considered to be executing its task.
• Waiting − Sometimes, a thread transitions to the waiting state while the thread waits for
another thread to perform a task. A thread transitions back to the runnable state only
when another thread signals the waiting thread to continue executing.
• Timed Waiting − A runnable thread can enter the timed waiting state for a specified interval
of time. A thread in this state transitions back to the runnable state when that time interval
expires or when the event it is waiting for occurs.
• Terminated (Dead) − A runnable thread enters the terminated state when it completes its
task or otherwise terminates.
Thread Priorities
• Every Java thread has a priority that helps the operating system determine
the order in which threads are scheduled.
• Java thread priorities are in the range between MIN_PRIORITY (a constant
of 1) and MAX_PRIORITY (a constant of 10). By default, every thread is
given priority NORM_PRIORITY (a constant of 5).
• Threads with higher priority are more important to a program and should
be allocated processor time before lower-priority threads. However, thread
priorities cannot guarantee the order in which threads execute and are very
much platform dependent.
Create a Thread by Implementing a Runnable Interface
• If your class is intended to be executed as a thread then you can achieve this
by implementing a Runnable interface. You will need to follow three basic
steps −
• Step 1: Implement run() Method
• As a first step, you need to implement a run() method provided by a
Runnable interface. This method provides an entry point for the thread and
you will put your complete business logic inside this method. Following is a
simple syntax of the run() method −
• public void run( )
• Step 2: Instantiate a Thread Object
• As a second step, you will instantiate a Thread object using the following
constructor −
• Thread(Runnable threadObj, String threadName);
• Where, threadObj is an instance of a class that implements the Runnable
interface and threadName is the name given to the new thread.
• Step 3: Call Thread using start() Method
• Once a Thread object is created, you can start it by calling start() method,
which executes a call to run( ) method. Following is a simple syntax of start()
method −
• void start();
Create Thread by Implementing Runnable Interface
that creates a new thread and starts running it −
class RunnableDemo implements Runnable {
private Thread t;
private String threadName;
RunnableDemo( String name) {
threadName = name;
System.out.println("Creating " + threadName );
}
public void run() {
System.out.println("Running " + threadName );
try {
for(int i = 4; i > 0; i--) {
System.out.println("Thread: " + threadName + ", " + i);
// Let the thread sleep for a while.
Thread.sleep(50);
}
catch (InterruptedException e) {
System.out.println("Thread " + threadName + " interrupted.");
}
System.out.println("Thread " + threadName + " exiting.");
}
public void start () {
System.out.println("Starting " + threadName );
if (t == null) {
t = new Thread (this, threadName);
t.start ();
}
}
}
public class TestThread {
public static void main(String args[]) {
RunnableDemo R1 = new RunnableDemo( "Thread-1");
R1.start();
RunnableDemo R2 = new RunnableDemo( "Thread-2");
R2.start();
}
}
Create a Thread by Extending a Thread Class
• The second way to create a thread is to create a new class that extends Thread
class using the following two simple steps. This approach provides more
flexibility in handling multiple threads created using available methods in
Thread class.
• Step 1: Override run() Method
• You will need to override run( ) method available in Thread class. This method
provides an entry point for the thread and you will put your complete business
logic inside this method. Following is a simple syntax of run() method −
public void run( )
• Step 2: Call Thread using start() Method
• Once Thread object is created, you can start it by calling start() method,
which executes a call to run( ) method. Following is a simple syntax of
start() method −
void start( );
Create Thread by Extending Thread Class
class ThreadDemo extends Thread {
private Thread t;
private String threadName;
ThreadDemo( String name) {
threadName = name; System.out.println("Creating " + threadName );
}
public void run() {
System.out.println("Running " + threadName );
try {
for(int i = 4; i > 0; i--) {
System.out.println("Thread: " + threadName + ", " + i);
// Let the thread sleep for a while.
Thread.sleep(50);
}
} catch (InterruptedException e) {
System.out.println("Thread " + threadName + " interrupted.");
}
System.out.println("Thread " + threadName + " exiting.");
}
public void start () {
System.out.println("Starting " + threadName );
if (t == null) {
t = new Thread (this, threadName);
t.start ();
}
}
}
public class TestThread {
public static void main(String args[]) {
ThreadDemo T1 = new ThreadDemo( "Thread-1");
T1.start();
ThreadDemo T2 = new ThreadDemo( "Thread-2");
T2.start();
}
}
Thread Methods
• public void start()
• Starts the thread in a separate path of execution, then invokes the run() method on this Thread object.
• public void run()
• If this Thread object was instantiated using a separate Runnable target, the run() method is invoked on that Runnable
object.
• public final void setName(String name)
• Changes the name of the Thread object. There is also a getName() method for retrieving the name.
• public final void setPriority(int priority)
• Sets the priority of this Thread object. The possible values are between 1 and 10.
• public final void setDaemon(boolean on)
• public final void join(long millisec)
• The current thread invokes this method on a second thread, causing the current thread to block
until the second thread terminates or the specified number of milliseconds passes.
• public void interrupt()
• Interrupts this thread, causing it to continue execution if it was blocked for any reason.
• public final boolean isAlive()
• Returns true if the thread is alive, which is any time after the thread has been started but before it
runs to completion.
Example for Demonstrating Thread States
• In this example, we're creating two threads by extending the Thread class.
We're printing each state of the thread. When a thread object is created, its
state is NEW; when start() method is called, state is START; when run()
method is called, state is RUNNING; When a thread finished the processing
the run() method, it went to DEAD state.
package com.tutorialspoint;
class ThreadDemo extends Thread {
private Thread t;
private String threadName;
ThreadDemo( String name) {
threadName = name;
System.out.println("Thread: " + threadName + ", " + "State: New");
}
public void run() {
System.out.println("Thread: " + threadName + ", " + "State: Running");
for(int i = 4; i > 0; i--) {
System.out.println("Thread: " + threadName + ", " + i);
}
System.out.println("Thread: " + threadName + ", " + "State: Dead");
}
public void start () {
System.out.println("Thread: " + threadName + ", " + "State: Start");
if (t == null) {
t = new Thread (this, threadName);
t.start ();
}
}
}
public class TestThread {
public static void main(String args[]) {
ThreadDemo thread1 = new ThreadDemo( "Thread-1");
ThreadDemo thread2 = new ThreadDemo( "Thread-2");
thread1.start();
thread2.start();
}
}
• In this example,we're using sleep() method to introduce some delay in processing and to show case the parallel processing using threads. We're creating two threads by
extending the Thread class. We're printing each state of the thread. When a thread object is created, its state is NEW; when start() method is called, state is START; when run()
method is called, state is RUNNING; in case sleep() is called, then thread goes to WAITING state; When a thread finished the processing the run() method, it went to DEAD state.
package com.tutorialspoint;
class ThreadDemo extends Thread {
private Thread t;
private String threadName;
ThreadDemo( String name) {
threadName = name;
System.out.println("Thread: " + threadName + ", " + "State: New");
}
public void run() {
System.out.println("Thread: " + threadName + ", " + "State: Running");
try {
for(int i = 4; i > 0; i--) {
System.out.println("Thread: " + threadName + ", " + i);
// Let the thread sleep for a while.
System.out.println("Thread: " + threadName + ", " + "State: Waiting");
Thread.sleep(50);
}
} catch (InterruptedException e) {
System.out.println("Thread " + threadName + " interrupted.");
}
System.out.println("Thread: " + threadName + ", " + "State: Dead");
}
public void start () {
System.out.println("Thread: " + threadName + ", " + "State: Start");
if (t == null) {
t = new Thread (this, threadName);
t.start ();
}
}
}
public class TestThread {
public static void main(String args[]) {
ThreadDemo thread1 = new ThreadDemo( "Thread-1");
ThreadDemo thread2 = new ThreadDemo( "Thread-2");
thread1.start();
thread2.start();
}}
Use getstate()
package com.tutorialspoint;
class ThreadDemo extends Thread {
private Thread t;
private String threadName;
ThreadDemo(String name) {
threadName = name;
System.out.println("Thread: " + threadName + ", State (constructor): " + getState());
}
public void run() {
System.out.println("Thread: " + threadName + ", State (run start): " + Thread.currentThread().getState());
try {
for (int i = 4; i > 0; i--) {
System.out.println("Thread: " + threadName + ", Count: " + i);
System.out.println("Thread: " + threadName + ", State (before sleep): " + Thread.currentThread().getState());
Thread.sleep(50);
System.out.println("Thread: " + threadName + ", State (after sleep): " + Thread.currentThread().getState());
}
} catch (InterruptedException e) {
System.out.println("Thread: " + threadName + " interrupted.");
}
System.out.println("Thread: " + threadName + ", State (end): " + Thread.currentThread().getState());
public void start() {
System.out.println("Thread: " + threadName + ", State (before start): " + getState());
if (t == null) {
t = new Thread(this, threadName);
System.out.println("Thread: " + threadName + ", State (after thread creation): " + t.getState());
t.start();
System.out.println("Thread: " + threadName + ", State (after start call): " + t.getState());
}
}
public Thread getInternalThread() {
return t;
}
public class TestThread {
public static void main(String args[]) throws InterruptedException {
ThreadDemo thread1 = new ThreadDemo("Thread-1");
ThreadDemo thread2 = new ThreadDemo("Thread-2");
thread1.start();
thread2.start();
// Optional: Wait and check final state
Thread.sleep(500); // Wait a bit for threads to finish
System.out.println("Final State of Thread-1: " + thread1.getInternalThread().getState());
System.out.println("Final State of Thread-2: " + thread2.getInternalThread().getState());
}
• Scenario: One thread takes customer orders (OrderThread), and another
thread serves food (ServeThread). Food should only be served after an
order is placed.
• Question:Implement this producer-consumer-like pattern using wait()
and notify().
• Concepts: Inter-thread communication, wait-notify, shared resource
• Sort an integer array using multiple threads
class FoodOrder {
private String foodItem;
private boolean isFoodReady = false;
// Producer method
public synchronized void placeOrder(String item) {
while (isFoodReady) {
try {
wait(); // Wait until the previous item is consumed
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.foodItem = item;
isFoodReady = true;
System.out.println("Producer placed order: " + item);
notify(); // Notify the consumer
}
// Consumer method
public synchronized void deliverOrder() {
while (!isFoodReady) {
try {
wait(); // Wait until an item is produced
} catch (InterruptedException e) { e.printStackTrace(); }
}System.out.println("Consumer received order: " + foodItem);
isFoodReady = false;
// Producer thread
class Producer extends Thread {
FoodOrder order;
Producer(FoodOrder order) {
this.order = order;
}
public void run() {
String[] foodItems = {"Pizza", "Burger", "Pasta", "Dosa"};
for (String item : foodItems) {
order.placeOrder(item);
try {
Thread.sleep(1000); // Simulate time to prepare food
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
// Consumer thread
class Consumer extends Thread {
FoodOrder order;
Consumer(FoodOrder order) {
this.order = order;
}
public void run() {
for (int i = 0; i < 4; i++) {
order.deliverOrder();
try {
Thread.sleep(1500); // Simulate time to consume food
} catch (InterruptedException e) {
e.printStackTrace();
}
} }}
// Main class
public class ProducerConsumerDemo {
public static void main(String[] args) {
FoodOrder order = new FoodOrder();
Producer producer = new Producer(order);
Consumer consumer = new Consumer(order);
producer.start();
consumer.start();
}