Friday, November 28, 2025

thumbnail

Multithreading and Concurrency in Java

Multithreading and Concurrency in Java


Java is a popular programming language for building high-performance applications. One of its key strengths is multithreading, which allows multiple tasks to run concurrently, improving efficiency and responsiveness.


This guide covers the fundamentals, key concepts, and practical usage of multithreading and concurrency in Java.


1. What Is Multithreading?


Multithreading is the ability of a program to execute two or more threads simultaneously. A thread is the smallest unit of execution in a program.


Benefits of Multithreading


Faster execution: Multiple tasks can run at the same time


Better resource utilization: CPU idle time is reduced


Responsive applications: UI threads can remain active while background tasks run


Example Use Cases


Running background tasks in a desktop application


Handling multiple client requests in a server


Parallel processing of large data


2. Creating Threads in Java


Java provides two main ways to create threads:


A. Extend the Thread Class

class MyThread extends Thread {

    public void run() {

        System.out.println("Thread is running: " + Thread.currentThread().getName());

    }

}


public class Main {

    public static void main(String[] args) {

        MyThread t1 = new MyThread();

        t1.start(); // Start a new thread

    }

}


B. Implement the Runnable Interface

class MyRunnable implements Runnable {

    public void run() {

        System.out.println("Runnable Thread: " + Thread.currentThread().getName());

    }

}


public class Main {

    public static void main(String[] args) {

        Thread t1 = new Thread(new MyRunnable());

        t1.start();

    }

}



Difference:


Thread class: Can’t extend any other class


Runnable interface: Allows extending another class


3. Thread Lifecycle


A thread in Java goes through several states:


New – Thread object is created


Runnable – Thread is ready to run


Running – Thread is executing


Waiting/Blocked – Thread waits for a resource


Timed Waiting – Thread waits for a specific time


Terminated – Thread has finished execution


4. Thread Methods in Java


start() – Starts the thread


run() – Contains code to execute


sleep(milliseconds) – Pauses thread


join() – Waits for another thread to finish


yield() – Temporarily pauses to let other threads run


setPriority() – Sets thread priority


5. Synchronization and Concurrency


When multiple threads access shared resources, race conditions can occur. Java provides tools to manage concurrency safely.


A. Synchronization


Prevents multiple threads from accessing a critical section simultaneously:


class Counter {

    private int count = 0;


    public synchronized void increment() {

        count++;

    }


    public int getCount() {

        return count;

    }

}


public class Main {

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

        Counter counter = new Counter();


        Runnable task = () -> {

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

                counter.increment();

            }

        };


        Thread t1 = new Thread(task);

        Thread t2 = new Thread(task);

        t1.start();

        t2.start();

        t1.join();

        t2.join();


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

    }

}


B. Locks and ReentrantLock


Advanced alternative to synchronized:


import java.util.concurrent.locks.Lock;

import java.util.concurrent.locks.ReentrantLock;


class Counter {

    private int count = 0;

    private Lock lock = new ReentrantLock();


    public void increment() {

        lock.lock();

        try {

            count++;

        } finally {

            lock.unlock();

        }

    }


    public int getCount() {

        return count;

    }

}


C. Volatile Variables


Used when multiple threads read/write a variable:


class SharedResource {

    public volatile boolean flag = true;

}



Ensures visibility across threads


Doesn’t guarantee atomicity


6. Executor Framework (Recommended for Modern Java)


Instead of creating threads manually, use ExecutorService for thread pools:


import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;


public class Main {

    public static void main(String[] args) {

        ExecutorService executor = Executors.newFixedThreadPool(3);


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

            int taskId = i;

            executor.submit(() -> {

                System.out.println("Task " + taskId + " is running on " + Thread.currentThread().getName());

            });

        }


        executor.shutdown(); // Stop accepting new tasks

    }

}



Benefits:


Reuses threads (performance)


Manages task queue automatically


Scales efficiently


7. Common Concurrency Issues


Race Conditions – Two threads modify shared data simultaneously


Deadlock – Two or more threads wait for each other forever


Starvation – Low-priority thread never gets CPU time


Livelock – Threads keep reacting to each other but make no progress


8. Java Concurrency Utilities


Java provides high-level APIs in java.util.concurrent:


ExecutorService – Thread pools and task management


CountDownLatch – Waits for multiple threads to finish


Semaphore – Limits concurrent access to resources


CyclicBarrier – Threads wait for each other at a barrier


ConcurrentHashMap – Thread-safe map


BlockingQueue – Thread-safe queues


9. Best Practices


Prefer ExecutorService over manually creating threads


Minimize shared mutable state


Use synchronized or Locks for shared resources


Avoid blocking the main thread


Use volatile for simple flags


Handle exceptions inside threads


Monitor and tune thread pool sizes


10. Summary


Multithreading enables concurrent execution in Java


Concurrency ensures safe, coordinated access to shared resources


Key tools: Thread, Runnable, synchronized, Lock, ExecutorService


Modern Java favors ExecutorService and high-level concurrency utilities


Proper design avoids race conditions, deadlocks, and starvation


Multithreading and concurrency are essential for high-performance, scalable, and responsive Java applications. 

Learn Full Stack JAVA Course in Hyderabad

Read More

Java 8 Features: Lambdas, Streams, and Functional Interfaces

Exception Handling in Java

Java Collections Framework: List, Set, Map

Java Data Types and Variables Explained

Visit Our Quality Thought Institute in Hyderabad

Get Directions

Subscribe by Email

Follow Updates Articles from This Blog via Email

No Comments

About

Search This Blog

Powered by Blogger.

Blog Archive