Day 1: Introduction to Java

icon picker
Day 12: Multithreading in Java

Welcome back to our journey through Java programming! Today, we're diving into one of the most powerful features of Java: Multithreading. Multithreading allows your Java applications to execute multiple threads concurrently, making them more efficient and responsive.
megaphone

Basics of Multithreading

Multithreading is the ability of a CPU or a single core in a multi-core processor to provide multiple threads of execution concurrently. In Java, a thread is the smallest unit of execution, and multithreading allows you to perform multiple tasks simultaneously.
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.
ok

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).
ok

Thread States and Lifecycle

Threads in Java have different states, and they go through various stages in their lifecycle. The main thread states are:
image.png
New: The thread has been created but not yet started.
Runnable: The thread is ready to run and waiting for CPU time.
Running: The thread is waiting for a monitor lock to enter a synchronized block/method.
Waiting: The thread is waiting for some condition to be satisfied.
Timed Waiting: The thread is waiting for a specific period.
Terminated: The thread has finished its execution.
You can transition between these states using methods like start(), join(), sleep(), and wait().

ok

Create a Thread by Implementing a Runnable Interface

In Java, there are two ways to create threads: by extending the Thread class or by implementing the Runnable interface. Here's an example of both approaches:
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

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

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

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();

Example

Here is an example 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();
}
}
megaphone

Output

Creating Thread-1
Starting Thread-1
Creating Thread-2
Starting Thread-2
Running Thread-1
Running Thread-2
Thread: Thread-2, 4
Thread: Thread-1, 4
Thread: Thread-1, 3
Thread: Thread-2, 3
Thread: Thread-1, 2
Thread: Thread-2, 2
Thread: Thread-2, 1
Thread: Thread-1, 1
Thread Thread-2 exiting.
Thread Thread-1 exiting.

Two methods Creating Threads

In Java, there are two ways to create threads: by extending the Thread class or by implementing the Runnable interface. Here's an example of both approaches:
javaCopy code
// Extending Thread class
class MyThread extends Thread {
public void run() {
// Code to be executed in this thread
}
}

// Implementing Runnable interface
class MyRunnable implements Runnable {
public void run() {
// Code to be executed in this thread
}
}

// Creating and starting threads
public class ThreadExample {
public static void main(String[] args) {
MyThread thread1 = new MyThread();
MyRunnable runnable = new MyRunnable();
Thread thread2 = new Thread(runnable);

thread1.start();
thread2.start();
}
}


Thread Methods

Following is the list of important methods available in the Thread class.
Table 3
Method & Description
1
public void start() Starts the thread in a separate path of execution, then invokes the run() method on this Thread object.
2
public void run() If this Thread object was instantiated using a separate Runnable target, the run() method is invoked on that Runnable object.
3
public final void setName(String name) Changes the name of the Thread object. There is also a getName() method for retrieving the name.
4
public final void setPriority(int priority) Sets the priority of this Thread object. The possible values are between 1 and 10.
5
public final void setDaemon(boolean on) A parameter of true denotes this Thread as a daemon thread.
6
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.
7
public void interrupt() Interrupts this thread, causing it to continue execution if it was blocked for any reason.
8
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.
There are no rows in this table

Synchronization

When multiple threads access shared resources concurrently, synchronization is crucial to prevent data corruption. You can use the synchronized keyword to create synchronized blocks or methods. Here's an example:
javaCopy code
class Counter {
private int count = 0;

public synchronized void increment() {
count++;
}

public synchronized int getCount() {
return count;
}
}

Some Thread Example

public class day12 implements Runnable{
private int number;
public day12(int number) {
this.number=number;
}


@Override
public void run() {
// TODO Auto-generated method stub
for (int i = 1; i <= 10; i++) {
System.out.printf("%s: %d * %d = %d\n", Thread.currentThread().getName(),
number, i, i * number);
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println("I will print table of 1 to 5 ");
for (int i = 1; i <= 5; i++) {
day12 mul = new day12(i);
Thread thread = new Thread(mul);
thread.start();
}
}

}



Dead Lock
class ThreadDeadLock
{
public static Object Lock1 = new Object();
public static Object Lock2 = new Object();

public static void main(String args[])
{
ThreadDemo1 T1 = new ThreadDemo1();
ThreadDemo2 T2 = new ThreadDemo2();
T1.start();
T2.start();
}

private static class ThreadDemo1 extends Thread
{
public void run()
{
synchronized (Lock1)
{
System.out.println("Thread 1: Holding lock 1...");
try
{
Want to print your doc?
This is not the way.
Try clicking the ⋯ next to your doc name or using a keyboard shortcut (
CtrlP
) instead.