Bytes
rocket

Your Success, Our Mission!

6000+ Careers Transformed.

Introduction to Multithreading

Last Updated: 23rd March, 2026

7.1 Introduction to Multithreading

7.1.1 Explanation

Multithreading is one of Java’s most powerful features that allows concurrent execution of two or more parts of a program — called threads — to maximize CPU utilization. Each thread runs independently, yet shares the same memory space, enabling parallel processing and efficient resource management.

In a single-threaded environment, only one task executes at a time. In contrast, multithreading allows multiple tasks to run simultaneously, improving responsivenessperformance, and throughput.

Threads can be created by either:

  1. Extending the Thread class and overriding its run() method, or
  2. Implementing the Runnable interface and passing an instance to a Thread object.

The Java Virtual Machine (JVM) manages thread scheduling and execution using a Thread Scheduler based on priorities and system load.
Java’s modern concurrency model (since Java 8+) enhances traditional threads with ExecutorsCallableFuture, and Virtual Threads (introduced in Java 21), simplifying concurrent programming for scalable applications.

7.1.2 Code

class MyThread extends Thread {

public void run() {

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

System.out.println(Thread.currentThread().getName() + " - Count: " + i);

try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); }

}

}

}

public class ThreadExample {

public static void main(String[] args) {

MyThread t1 = new MyThread();

MyThread t2 = new MyThread();

t1.start();  // starts first thread

t2.start();  // starts second thread

System.out.println("Main thread completed.");

}

}

7.1.3 Example

Possible Output (interleaved):

Thread-0 - Count: 1

Thread-1 - Count: 1

Thread-0 - Count: 2

Thread-1 - Count: 2

...

Main thread completed.

Explanation:
Two threads (t1 and t2) execute concurrently, printing their counts asynchronously.
The sleep() method pauses each thread briefly, allowing interleaving of execution.
This demonstrates true parallel behavior controlled by the JVM’s thread scheduler.

7.1.4 Use Cases

  • Running background tasks in desktop or server applications.
  • Performing parallel data processing in analytics pipelines.
  • Enhancing performance in I/O-bound or computation-heavy systems.
  • Improving responsiveness in GUI or real-time applications.

7.1.5 Relevant Table

Component

Description

Example

Thread

Unit of execution

Thread t = new Thread();

Runnable

Interface defining run()

class A implements Runnable

sleep()

Pauses execution temporarily

Thread.sleep(1000)

start()

Begins a new thread

t.start();

join()

Waits for thread to finish

t.join();

7.2 Runnable Interface and Thread Lifecycle

7.2.1 Explanation

The Runnable interface is a functional interface that defines a single method run(). It provides a cleaner, more flexible way to define tasks separate from the thread itself, enabling reuse with different thread pools or executor services.

When a Runnable object is passed to a Thread constructor, the run() method defines what the thread executes. This approach decouples task definition from thread control, which is considered best practice in modern Java design.

A thread in Java follows a lifecycle managed by the JVM:

  1. New: Thread created but not started.
  2. Runnable: Ready to execute, waiting for CPU time.
  3. Running: Actively executing code.
  4. Blocked/Waiting: Paused for resources or synchronization.
  5. Terminated: Completed execution.

Developers can control this lifecycle using methods like start(), sleep(), join(), and interrupt().
Understanding thread states is essential for diagnosing concurrency bugs and optimizing performance.

7.2.2 Code

class Task implements Runnable {

public void run() {

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

System.out.println(Thread.currentThread().getName() + " executing task...");

try { Thread.sleep(400); } catch (InterruptedException e) { e.printStackTrace(); }

}

}

}

public class RunnableDemo {

public static void main(String[] args) throws InterruptedException {

Thread thread1 = new Thread(new Task(), "Worker-1");

Thread thread2 = new Thread(new Task(), "Worker-2");

thread1.start();

thread2.start();

thread1.join(); // Waits for completion

thread2.join();

System.out.println("All tasks completed.");

}

}

7.2.3 Example

Output:

Worker-1 executing task...

Worker-2 executing task...

Worker-1 executing task...

Worker-2 executing task...

All tasks completed.

Explanation:
Each worker thread runs concurrently, performing the same task.
The join() method ensures the main thread waits for both to finish, demonstrating thread coordination and synchronization in execution order.

7.2.4 Use Cases

  • Defining reusable, concurrent tasks without subclassing Thread.
  • Executing multiple independent operations simultaneously.
  • Creating concurrent web servers or task processors.
  • Managing workloads in parallel computing environments.

7.2.5 Relevant Table

Thread State

Description

Method / Trigger

New

Created but not started

new Thread()

Runnable

Ready for CPU allocation

start()

Running

Executing code

Scheduler assigns CPU

Blocked/Waiting

Waiting for lock/resource

wait()sleep()

Terminated

Finished execution

Method ends

7.3 Synchronization and Inter-thread Communication

7.3.1 Explanation

In multithreaded applications, multiple threads may try to access shared resources simultaneously, leading to data inconsistency or race conditions.
Java solves this problem using synchronization, which ensures that only one thread accesses a shared resource at a time.

The synchronized keyword can be applied to methods or code blocks to enforce mutual exclusion. This creates a lock on the resource, preventing others from modifying it concurrently.

Java also provides inter-thread communication mechanisms using wait(), notify(), and notifyAll(), allowing threads to coordinate execution by pausing and resuming based on conditions.
Since Java 5+, higher-level concurrency utilities like ReentrantLockSemaphore, and CountDownLatch in java.util.concurrent offer more flexibility and control.

Synchronization must be used carefully to avoid deadlocks (when two threads wait indefinitely for each other’s locks).

7.3.2 Code

class Counter {

private int count = 0;

public synchronized void increment() {

count++;

}

public int getCount() {

return count;

}

}

public class SyncExample {

public static void main(String[] args) throws InterruptedException {

Counter counter = new Counter();

Thread t1 = new Thread(() -> {

for (int i = 0; i < 1000; i++) counter.increment();

});

Thread t2 = new Thread(() -> {

for (int i = 0; i < 1000; i++) counter.increment();

});

t1.start();

t2.start();

t1.join();

t2.join();

System.out.println("Final Count: " + counter.getCount());

}

}

7.3.3 Example

Output:

Final Count: 2000

Explanation:
Without synchronization, the result would vary due to race conditions.
By marking increment() as synchronized, only one thread at a time can modify count, ensuring data integrity.

7.3.4 Use Cases

  • Banking systems (avoiding balance inconsistencies).

  • Inventory management (preventing double updates).

  • Logging systems (thread-safe file writes).

  • Thread communication in real-time applications.

     

7.3.5 Relevant Table

Concept

Description

Example

Synchronization

Mutual exclusion for shared resources

synchronized block

Inter-thread Communication

Threads signaling each other

wait()notify()

Deadlock

Circular lock dependency

Improper nested locks

ReentrantLock

Advanced lock mechanism

lock.lock()lock.unlock()

Module 7: Multithreading and ConcurrencyIntroduction to Multithreading

Top Tutorials

Logo
Computer Science

CNN in Deep Learning 2026

A beginner-friendly guide to CNNs: understand deep learning essentials, create Python-based models, and explore advanced applications.

4 Modules12 Lessons151 Learners
Start Learning
Logo
Computer Science

Breaking The Limits: Scaling Databases with MySQL Partitioning

Learn MySQL partitioning with examples. Improve query performance, scalability, and data management using RANGE, LIST, HASH, KEY, and composite techniques.

7 Modules11 Lessons71 Learners
Start Learning
Logo

ML in Action: Hands-On Guide to Deploying and Serving Models

Learn model deployment and serving—from concepts to real-world architectures, tools, APIs, containers, and cloud workflows for production-ready ML.

4 Modules10 Lessons78 Learners
Start Learning
  • Official Address
  • 4th floor, 133/2, Janardhan Towers, Residency Road, Bengaluru, Karnataka, 560025
  • Communication Address
  • Follow Us
  • facebookinstagramlinkedintwitteryoutubetelegram

© 2026 AlmaBetter