HOME HTML EDITOR C JAVA PHP

Java Multithreading: Unleashing Parallel Power

Multithreading in Java is a feature that allows concurrent execution of two or more parts of a program for maximum utilization of the CPU. Each part of such a program is called a thread. So, threads are light-weight processes within a process.

1. The Lifecycle of a Thread

A thread does not just "run." It moves through a specific set of states managed by the JVM and the underlying Operating System. Understanding these states is critical for debugging deadlocks and performance issues.

State Description
NewThread is created but start() hasn't been called.
RunnableReady to run and waiting for CPU time from the scheduler.
BlockedWaiting for a monitor lock to enter a synchronized block.
WaitingWaiting indefinitely for another thread to perform an action.
Timed WaitingWaiting for a specified amount of time (e.g., sleep(1000)).
TerminatedExecution has finished.

2. Two Ways to Create a Thread

Java provides two primary mechanisms to define a thread's task. While both achieve the same goal, one is generally preferred in professional development.

1. Extending the Thread Class

Create a class that extends Thread and override the run() method. This is simpler but limits your class from extending anything else (Java's single inheritance rule).

2. Implementing Runnable (Recommended)

Implement the Runnable interface. This is more flexible as your class can still extend another class. It separates the "Task" from the "Thread Runner."

3. Synchronization: Preventing Chaos

When multiple threads try to access the same data (like a bank balance) at the same time, you get a Race Condition. Java uses the synchronized keyword to ensure that only one thread can access a resource at a time.

The Monitor Lock: Every object in Java has a "Monitor." When a thread enters a synchronized method, it "takes the key." Other threads must wait until the key is returned.

4. Thread Inter-communication

Threads often need to talk to each other. For example, a "Producer" thread creates data and needs to tell a "Consumer" thread that data is ready. This is handled by three methods from the Object class:

5. Mastery Code Example: The Shared Counter

This example demonstrates how two threads can safely increment a shared variable using synchronization.

class Counter {
  private int count = 0;
  // synchronized ensures atomic updates
  public synchronized void increment() { count++; }
  public int getCount() { return count; }
}

public class ThreadPro {
  public static void main(String[] args) throws InterruptedException {
    Counter c = new Counter();
    Runnable task = () -> {
      for(int i=0; i<1000; i++) c.increment();
    };

    Thread t1 = new Thread(task);
    Thread t2 = new Thread(task);
    t1.start(); t2.start();
    t1.join(); t2.join(); // Wait for both to finish
    System.out.println("Final Count: " + c.getCount());
  }
}

6. The Volatile Keyword

In a multi-core system, threads might cache variables in CPU registers for speed. This means one thread might not see a change made by another. The volatile keyword tells the JVM: "Always read this variable from main memory, never cache it."

7. Deadlocks: The Silent Killer

A **Deadlock** happens when Thread A is waiting for a lock held by Thread B, while Thread B is waiting for a lock held by Thread A. Neither can move, and the program freezes forever.

Prevention: Always acquire locks in the same order across all threads, or use tryLock() from the java.util.concurrent package.

8. Interview Preparation: Senior Thread Q&A

Q: What is the difference between start() and run()?
A: start() creates a new call stack and triggers the thread. Calling run() directly just executes the code in the current thread like a normal method call.

Q: What does join() do?
A: It pauses the execution of the current thread until the thread on which join() was called finishes. It's used for synchronization points.

Q: Why is stop() deprecated?
A: Because it is inherently unsafe. Stopping a thread abruptly leaves shared data in an inconsistent state and doesn't release locks properly. Use "interrupts" instead.

Final Verdict

Java Multithreading is what makes applications feel fluid and professional. While it introduces complexities like race conditions and deadlocks, mastering synchronization and thread communication allows you to build high-performance systems. In modern Java, we also use the ExecutorService and CompletableFuture to manage threads even more efficiently.

Next: Mastering ExecutorService →