[Go to site: main page, start]

0% found this document useful (0 votes)
3 views20 pages

Java Multithreading MasterGuide

This document serves as a comprehensive guide on Java multithreading and synchronization, covering key concepts such as thread lifecycle, creation methods, synchronization techniques, and inter-thread communication. It includes practical examples and templates for implementing multithreading in various scenarios, along with best practices for file handling and custom exceptions. The guide emphasizes the importance of synchronization to prevent race conditions and provides a structured approach to solving common programming problems using multithreading.

Uploaded by

mithil27360
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
3 views20 pages

Java Multithreading MasterGuide

This document serves as a comprehensive guide on Java multithreading and synchronization, covering key concepts such as thread lifecycle, creation methods, synchronization techniques, and inter-thread communication. It includes practical examples and templates for implementing multithreading in various scenarios, along with best practices for file handling and custom exceptions. The guide emphasizes the importance of synchronization to prevent race conditions and provides a structured approach to solving common programming problems using multithreading.

Uploaded by

mithil27360
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd

Java Multithreading &

Synchronization
Master Guide — Solve Any Question
OOP + Threads + Synchronization + File Handling

1. Thread Lifecycle — States & Transitions

Thread States (know all 6!)


NEW → Thread object created, start() not called yet
RUNNABLE → Running OR ready to run (in thread scheduler queue)
BLOCKED → Waiting to acquire a synchronized lock
WAITING → wait() called — needs notify()/notifyAll() to resume
TIMED_WAITING→ sleep(ms), wait(ms), join(ms) — auto-wakes after time
TERMINATED → run() method finished or exception thrown

State Transition Flow:

Lifecycle Diagram (text form)


new Thread() ──► NEW
.start() ──► RUNNABLE ◄──────────────────────┐
│ │
synchronized block waiting ──► BLOCKED ──┘

wait() ──► WAITING ──► notify() ──► RUNNABLE
sleep(ms) ──► TIMED_WAITING ──► (timeout) ──► RUNNABLE
run() ends ──► TERMINATED
2. Creating Threads — 3 Ways

Way 1: Extend Thread

Extend Thread class


class BattingThread extends Thread {
private Batsman batsman;
BattingThread(Batsman b) { [Link] = b; }

@Override
public void run() {
// Thread logic here
[Link](4);
}
}
// Usage:
BattingThread t = new BattingThread(batsman);
[Link](); // ← ALWAYS start(), NEVER run()

Way 2: Implement Runnable (Preferred)

Implement Runnable interface


class BookingTask implements Runnable {
private String customerName;
BookingTask(String name) { [Link] = name; }

@Override
public void run() {
// Task logic here
[Link](customerName + " booking room...");
}
}
// Usage:
Thread t = new Thread(new BookingTask("Alice"));
[Link]();

// Or with lambda (Java 8+):


Thread t2 = new Thread(() -> [Link]("Lambda thread"));
[Link]();
Way 3: Implement Callable (returns a value)

Callable + Future
class FareCalculator implements Callable<Double> {
@Override
public Double call() throws Exception {
return 250.0; // Returns a value unlike Runnable
}
}
ExecutorService executor = [Link](3);
Future<Double> future = [Link](new FareCalculator());
Double result = [Link](); // Blocks until done

Key Rule
Always call .start() — NOT .run(). Calling .run() executes on the current thread — no new thread
is created!
start() → registers with scheduler → OS picks it up → calls run() internally.
3. Synchronization — The Core Concept

Synchronization ensures only ONE thread executes a critical section at a time, preventing race
conditions.

3.1 Synchronized Method

Synchronized method — locks 'this' object


class BankAccount {
private double balance = 5000;

// Only ONE thread can execute this at a time


public synchronized void withdraw(double amount) {
if (balance >= amount) {
balance -= amount;
[Link]("Withdrawn: " + amount);
} else {
[Link]("Insufficient balance!");
}
}

public synchronized void deposit(double amount) {


balance += amount;
}

public synchronized double getBalance() { return balance; }


}

3.2 Synchronized Block (Fine-Grained Control)

Synchronized block — better performance


public void processBooking(String customer) {
// Non-critical code runs freely (no lock needed)
[Link](customer + " processing...");

synchronized (this) { // ← Lock ONLY for critical section


// CRITICAL: check availability + assign room
if (availableRooms > 0) {
availableRooms--;
assignRoom(customer);
}
}
// More non-critical code...
}

3.3 Static Synchronization (Class-Level Lock)

Static synchronized — locks the Class object


class TicketCounter {
private static int ticketCount = 1000;

// Locks [Link] — NOT any instance


public static synchronized boolean bookTicket() {
if (ticketCount > 0) {
ticketCount--;
return true;
}
return false;
}
}

Type When to Use


synchronized method When entire method is critical — simple, clean
synchronized block When only part of method is critical — better perf
static synchronized When shared state is a static variable across all instances
ReentrantLock When you need tryLock(), timeout, or fairness control
4. wait() / notify() / notifyAll()

These methods enable inter-thread communication. Used to make one thread WAIT for a condition and
another thread SIGNAL when ready.

CRITICAL RULE
wait(), notify(), notifyAll() MUST be called inside a synchronized block/method.
Otherwise you get: IllegalMonitorStateException!

4.1 Producer-Consumer Pattern (The Universal Template)

Producer-Consumer — used in ALL 20 questions


class SharedResource {
private boolean resourceAvailable = false;

// CONSUMER — waits for resource


public synchronized void consume() throws InterruptedException {
while (!resourceAvailable) { // ← while loop, NOT if
wait(); // releases lock + sleeps
}
// Use the resource
resourceAvailable = false;
[Link]("Consumed!");
notifyAll(); // wake up waiting producers
}

// PRODUCER — signals when resource ready


public synchronized void produce() throws InterruptedException {
while (resourceAvailable) { // ← wait if already full
wait();
}
resourceAvailable = true;
[Link]("Produced!");
notifyAll(); // wake up waiting consumers
}
}

4.2 Hotel Room / Seat Booking Pattern

Wait when full, notify on release — used in Q2, Q4, Q5, Q6, Q13...
class BookingSystem {
private int availableRooms = 5;
public synchronized void bookRoom(String customer)
throws InterruptedException {
while (availableRooms == 0) { // ← WHILE not IF (spurious
wakeups!)
[Link](customer + " waiting for room...");
wait();
}
availableRooms--;
[Link](customer + " booked a room. Remaining: " +
availableRooms);
}

public synchronized void checkOut(String customer) {


availableRooms++;
[Link](customer + " checked out.");
notifyAll(); // ← wake ALL waiting customers
}
}

Why WHILE and not IF?


Spurious wakeups: A thread can wake up from wait() WITHOUT being notified (rare but possible
in JVM).
Use while loop so the condition is RE-CHECKED after waking up.
If you use if and a spurious wakeup occurs, the thread proceeds even though condition is still
false — BUG!

4.3 wait() vs sleep() — Critical Difference


Feature wait() vs sleep()
wait() Releases the lock. Thread waits until notify(). Must be in
synchronized block.
sleep(ms) Does NOT release the lock. Thread pauses for given time. Can be
called anywhere.
notified by wait() → needs notify() or notifyAll(). sleep() → wakes automatically.
used for wait() → inter-thread communication. sleep() → pausing execution.
5. OOP Patterns in All Questions

5.1 The Standard OOP Blueprint (Repeated Every Question)


Every question follows THIS structure — memorize it:

Blueprint: Interface → Abstract Class → Concrete Class


// Step 1: Interface (defines contract)
interface BattingOperations {
void playShot(int runs);
void getOut();
}

// Step 2: Abstract base class (shared fields + abstract method)


abstract class CricketPlayer {
protected String name;
protected int totalRuns;
protected boolean isOut;

CricketPlayer(String name) {
[Link] = name;
[Link] = 0;
[Link] = false;
}

abstract void performAction(); // force subclass to implement


}

// Step 3: Concrete class (extends abstract + implements interface)


class Batsman extends CricketPlayer implements BattingOperations {
Batsman(String name) { super(name); }

@Override
public synchronized void playShot(int runs) {
if (!isOut) {
totalRuns += runs;
[Link]("Runs: " + runs + " | Total: " +
totalRuns);
}
}

@Override
public synchronized void getOut() {
if (!isOut) { // ensures dismissal recorded only once
isOut = true;
[Link](name + " is OUT! Final: " + totalRuns);
}
}

@Override
void performAction() { [Link]("Batting!"); }
}

5.2 Enum Pattern

Enum with constructor (used in EVERY question)


enum ShotType {
SINGLE(1), DOUBLE(2), FOUR(4), SIX(6), OUT(0);

private final int runs;

ShotType(int runs) { // ← constructor


[Link] = runs;
}

public int getRuns() { // ← getter


return runs;
}
}

// Usage:
ShotType shot = [Link];
[Link]([Link]()); // prints: 6
[Link]([Link]()); // prints: SIX

// Iterating all values:


for (ShotType s : [Link]()) {
[Link](s + " = " + [Link]());
}

5.3 Abstract Method + Override Pattern

Abstract class with different implementations


abstract class Room {
protected int roomNo;
protected double basePrice;

abstract double calculateTariff(int days); // ← must override


}
class StandardRoom extends Room {
@Override
public double calculateTariff(int days) {
return basePrice * days; // base rate
}
}

class DeluxeRoom extends Room {


@Override
public double calculateTariff(int days) {
return basePrice * days * 1.5; // 1.5x multiplier
}
}

class SuiteRoom extends Room {


@Override
public double calculateTariff(int days) {
return basePrice * days * 2.5; // 2.5x multiplier
}
}
6. Custom Exceptions

Custom Exception Template


// Step 1: Create the exception class
class BedNotAvailableException extends Exception {
public BedNotAvailableException(String message) {
super(message);
}
}

// Step 2: Throw it
public void admitPatient(Patient p) throws BedNotAvailableException {
if (availableBeds == 0) {
throw new BedNotAvailableException(
"No beds available in " + wardType + " ward!");
}
availableBeds--;
}

// Step 3: Catch it
try {
[Link](patient);
} catch (BedNotAvailableException e) {
[Link]("Exception: " + [Link]());
}

Custom Exception Question Used In


BedNotAvailableExceptio Q6 — Hospital Bed Allocation
n
OutOfStockException Q8 — E-Commerce Inventory
BookNotAvailableExcepti Q10 — Library Book Borrowing
on
BorrowingLimitExceeded Q10 — Library Book Borrowing
Exception
InvalidTransactionExcept Bonus — Library Lending (Exam Paper)
ion
7. File Handling with Threads

7.1 Writing to a Log File (Thread-Safe)

Synchronized file writing — used in ALL file-handling questions


import [Link].*;

class Logger {
private static final String LOG_FILE = "[Link]";

// synchronized ensures no two threads write simultaneously


public static synchronized void log(String message) {
try (FileWriter fw = new FileWriter(LOG_FILE, true); // true =
append
BufferedWriter bw = new BufferedWriter(fw)) {

[Link](message);
[Link]();

} catch (IOException e) {
[Link]("Log error: " + [Link]());
}
}
}

// Usage from any thread:


[Link]("[DEPOSIT] Rs.5000 | Balance: Rs.15000 | " + new
[Link]());

7.2 Reading from a File

Reading file contents


public static String readFile(String filename) {
StringBuilder sb = new StringBuilder();
try (FileReader fr = new FileReader(filename);
BufferedReader br = new BufferedReader(fr)) {

String line;
while ((line = [Link]()) != null) {
[Link](line).append("\n");
}
} catch (IOException e) {
[Link]("Read error: " + [Link]());
}
return [Link]();
}

7.3 Unbuffered Streams (Exam Bonus Question)

FileWriter + FileReader WITHOUT BufferedWriter/Reader


// UNBUFFERED writing (FileWriter directly)
try (FileWriter fw = new FileWriter("[Link]", true)) {
[Link](message + "\n");
// No buffering — writes directly to disk
} catch (IOException e) { [Link](); }

// UNBUFFERED reading (FileReader directly)


try (FileReader fr = new FileReader("[Link]")) {
int ch;
StringBuilder sb = new StringBuilder();
while ((ch = [Link]()) != -1) { // reads char by char
[Link]((char) ch);
}
[Link]([Link]());
} catch (IOException e) { [Link](); }
8. Complete Thread Templates for Any Question

8.1 Multi-Thread with Shared Resource (Core Template)


This template solves Q2, Q4, Q5, Q6, Q9, Q13, Q15, Q18, Q19, Q20...

Universal Thread Template — adapt for any question


class SharedSystem {
private int capacity; // e.g., rooms, beds, seats, slots
private int current = 0;

SharedSystem(int capacity) {
[Link] = capacity;
}

// Called by customer/patient/student threads


public synchronized void requestAccess(String entityName)
throws InterruptedException {
while (current >= capacity) {
[Link](entityName + " waiting...");
wait();
}
current++;
[Link](entityName + " got access. Used: " + current +
"/" + capacity);
[Link](entityName + " accessed at " + new [Link]());
}

// Called when customer/patient/student leaves


public synchronized void releaseAccess(String entityName) {
current--;
[Link](entityName + " released. Available: " +
(capacity - current));
[Link](entityName + " released at " + new [Link]());
notifyAll();
}
}

// Thread for each customer/student/patient


class EntityThread extends Thread {
private SharedSystem system;
private String name;
private int stayDuration; // ms for simulation

EntityThread(SharedSystem sys, String name, int duration) {


[Link] = sys;
[Link] = name;
[Link] = duration;
}

@Override
public void run() {
try {
[Link](name);
[Link](stayDuration); // simulate stay
[Link](name);
} catch (InterruptedException e) {
[Link]().interrupt();
}
}
}

// Main — launch multiple threads


public class Main {
public static void main(String[] args) {
SharedSystem hotel = new SharedSystem(3); // 3 rooms
String[] customers = {"Alice", "Bob", "Charlie", "Dave", "Eve"};

for (String c : customers) {


new EntityThread(hotel, c, 2000).start();
}
}
}

8.2 Three-Thread Coordination (Q1 Cricket / Exam Pattern)

3 threads coordinating on shared object


// Thread 1: Active actor (batsman, student, customer)
class Thread1_Actor extends Thread {
private SharedObject obj;
@Override
public void run() {
// Does work, checks if stopped
while (![Link]()) {
[Link]();
try { [Link](500); } catch (InterruptedException e)
{ break; }
}
}
}

// Thread 2: Disruptor (fielder, librarian, checkout)


class Thread2_Disruptor extends Thread {
private SharedObject obj;
@Override
public void run() {
try { [Link](2000); } catch (InterruptedException e)
{ return; }
[Link](); // cause dismissal/return/checkout
}
}

// Thread 3: Monitor (umpire, moderator, supervisor)


class Thread3_Monitor extends Thread {
private SharedObject obj;
private Thread1_Actor actor;
private Thread2_Disruptor disruptor;

@Override
public void run() {
try {
[Link](); // wait for actor to finish
[Link](); // wait for disruptor to finish
} catch (InterruptedException e) { return; }
[Link]("[Monitor] All operations complete!");
[Link]("[Monitor] Final result: " + [Link]());
}
}
9. Common Mistakes & How to Fix Them

Mistake Fix
Calling .run() instead Always use .start() to create a new thread
of .start()
Using if instead of while Use while loop — spurious wakeups exist
for wait()
wait()/notify() outside Must be inside synchronized block/method
synchronized
Not handling Add try-catch or declare throws InterruptedException
InterruptedException
Race condition on Add synchronized to methods that read/write it
shared variable
Forgetting Check flag before acting, set it inside synchronized block
isOut/isAvailable check
Multiple dismissal Use if(!isOut) inside synchronized to ensure single update
records
File write corruption Make log() method static synchronized
across threads
Deadlock (threads wait Always lock in same order, avoid nested locks
for each other)
Not calling notifyAll() on notifyAll() in release method wakes all waiters
release

Deadlock Avoidance

Deadlock example and fix


// DEADLOCK — Thread A locks obj1 then obj2,
// Thread B locks obj2 then obj1 → they wait forever

// FIX: Always lock in the SAME ORDER


// Thread A: synchronized(obj1) { synchronized(obj2) { ... } }
// Thread B: synchronized(obj1) { synchronized(obj2) { ... } } ← same
order

// Or use tryLock() with timeout (ReentrantLock):


ReentrantLock lock1 = new ReentrantLock();
ReentrantLock lock2 = new ReentrantLock();

if ([Link](1, [Link])) {
try {
if ([Link](1, [Link])) {
try { /* critical section */ }
finally { [Link](); }
}
} finally { [Link](); }
}
10. Quick Reference Cheatsheet

Methods Cheatsheet
Method / Keyword Description
synchronized (method) Locks 'this'. Only 1 thread enters at a time.
synchronized (block) synchronized(obj) { } — locks specific object
wait() Releases lock, thread sleeps until notify(). Must be in synchronized.
notify() Wakes ONE randomly chosen waiting thread.
notifyAll() Wakes ALL waiting threads. Prefer over notify().
[Link](ms) Pauses thread for ms milliseconds. Does NOT release lock.
[Link]() Calling thread waits for thread t to finish.
[Link]() Creates new thread and starts execution of run().
[Link]() Sets interrupt flag. Use [Link]().interrupt() in catch.
volatile keyword Ensures variable is read/written from main memory, not cache.
AtomicInteger Thread-safe integer. incrementAndGet(), decrementAndGet(), etc.

Synchronized vs volatile vs Atomic


Tool Use When
synchronized Multiple operations must be atomic (check-then-act, read-modify-
write)
volatile Only ONE variable, only simple read/write, no compound operations
AtomicInteger/Long Single counter that's incremented/decremented by many threads
ReentrantLock Need tryLock, fairness, or multiple conditions (Condition objects)

The Universal Answer Template

Steps to solve ANY multithreading question


STEP 1: Identify shared resource (rooms, seats, balance, stock, beds...)
STEP 2: Create class with counter + synchronized requestAccess() +
releaseAccess()
STEP 3: Use while + wait() in requestAccess()
STEP 4: Use notifyAll() in releaseAccess()
STEP 5: Create Thread/Runnable for each actor (customer, student,
patient...)
STEP 6: In run(), call requestAccess → sleep → releaseAccess
STEP 7: Add synchronized Logger class for file output
STEP 8: In main(), create threads in a loop, start() all of them
STEP 9: Optionally join() threads to wait for all to finish before final
output

Master these 4 things and you can solve all 20 questions:

Interface → Abstract Class → Concrete Class | Enum with constructor | synchronized +


wait/notify | synchronized Logger

You might also like