1. What is Multithreading?
Multitasking: Performing multiple tasks simultaneously.
- Process-based: Multiple programs (e.g., browser + music player).
- Thread-based: Multiple parts of a single program.
- Thread: Smallest unit of execution inside a process.
- Multithreading: Running multiple threads concurrently to improve performance.
java.lang.Thread, Runnable).2. Thread Lifecycle (States)
A thread goes through these states:
- New → Created but not started.
- Runnable → Ready to run (after
start()). - Running → Thread scheduler picks it.
- Waiting/Timed Waiting → Waiting for another thread (via
join(),sleep(), etc.). - Terminated → Thread finishes execution.
3. Creating Threads
(a) Extending Thread class
class MyThread extends Thread {
public void run() {
System.out.println("Thread running: " + Thread.currentThread().getName());
}
}
public class ThreadDemo {
public static void main(String[] args) {
MyThread t1 = new MyThread();
t1.start(); // starts new thread
}
}
(b) Implementing Runnable interface
class MyRunnable implements Runnable {
public void run() {
System.out.println("Thread running: " + Thread.currentThread().getName());
}
}
public class RunnableDemo {
public static void main(String[] args) {
Thread t1 = new Thread(new MyRunnable());
t1.start();
}
}
👉 Runnable is preferred since Java allows multiple inheritance through interfaces.
(c) Using Lambda (Java 8+)
public class LambdaThreadDemo {
public static void main(String[] args) {
Thread t1 = new Thread(() -> System.out.println("Thread running"));
t1.start();
}
}
4. Thread Methods
| Method | Description |
|---|---|
start() |
Starts a new thread, calls run() internally. |
run() |
Defines task, but doesn’t create a new thread if called directly. |
sleep(ms) |
Pause thread for given milliseconds. |
join() |
Waits for another thread to finish. |
yield() |
Gives chance to other threads of equal priority. |
setPriority() |
Set thread priority (1–10). |
isAlive() |
Checks if thread is alive. |
5. Thread Priority
- Range: 1 (MIN) → 10 (MAX)
- Default = 5 (NORM_PRIORITY)
Thread t1 = new Thread();
t1.setPriority(Thread.MAX_PRIORITY);
⚠️ Thread scheduling depends on OS + JVM, so priorities are only hints.
6. Thread Synchronization
Problem: Race condition – When multiple threads modify shared data at the same time.
Without Synchronization:
class Counter {
int count = 0;
public void increment() {
count++;
}
}
public class SyncDemo {
public static void main(String[] args) throws Exception {
Counter c = new Counter();
Thread t1 = new Thread(() -> { for(int i=0;i<1000;i++) c.increment(); });
Thread t2 = new Thread(() -> { for(int i=0;i<1000;i++) c.increment(); });
t1.start(); t2.start();
t1.join(); t2.join();
System.out.println(c.count); // Expected: 2000, Actual: less (race condition!)
}
}
With Synchronization:
class Counter {
int count = 0;
public synchronized void increment() {
count++;
}
}
👉 synchronized ensures only one thread executes the method at a time.
7. Inter-thread Communication
Threads can communicate using:
(a) wait(), notify(), notifyAll()
class Shared {
boolean ready = false;
synchronized void produce() {
System.out.println("Producing...");
ready = true;
notify(); // notify waiting thread
}
synchronized void consume() throws InterruptedException {
while(!ready) {
wait(); // wait until producer notifies
}
System.out.println("Consumed!");
}
}
8. Deadlock
When two or more threads wait forever for resources.
Example:
class A { synchronized void methodA(B b) { b.last(); } synchronized void last() {} }
class B { synchronized void methodB(A a) { a.last(); } synchronized void last() {} }
👉 Always acquire locks in the same order to avoid deadlocks.
9. Thread Pools (Executor Framework)
Instead of creating threads manually, use Executors.
import java.util.concurrent.*;
public class ThreadPoolDemo {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(2);
for (int i = 1; i <= 5; i++) {
int taskId = i;
executor.execute(() -> System.out.println("Task " + taskId + " executed by " + Thread.currentThread().getName()));
}
executor.shutdown();
}
}
👉 Efficient, reusable threads → avoids performance overhead.
10. Advanced Concepts
- Callable & Future: Return results from threads.
- ReentrantLock: Advanced synchronization mechanism.
- Atomic Variables:
AtomicInteger,AtomicBooleanfor lock-free thread safety. - Concurrent Collections:
ConcurrentHashMap,CopyOnWriteArrayList.
11. Interview-Focused FAQs
Q1: Difference between Thread and Runnable?
Thread: Extends class, less flexible.Runnable: Implements interface, preferred.
Q2: What is synchronization?
- Mechanism to prevent race conditions by allowing one thread at a time.
Q3: What is deadlock? How to prevent it?
- Two threads waiting for each other → infinite wait.
- Prevent by acquiring locks in same order or using tryLock().
Q4: What is difference between sleep() and wait()?
sleep() → doesn’t release lock.wait() → releases lock, used for inter-thread communication.
Q5: Difference between ExecutorService and creating threads manually?
- ExecutorService manages a pool of threads → more efficient.
12. Best Practices
- Use Executor framework over manually managing threads.
- Minimize use of
synchronized→ considerConcurrentclasses. - Always handle
InterruptedException. - Avoid deadlocks → acquire locks in order.
- Use atomic classes for simple counters.
Next: Chapter 20 – Java Collections Framework (Master Guide)