Interactive Java Multi-Threading Tutorial
Multi-threading is a programming concept where multiple threads run concurrently within a single process, allowing multiple tasks to be executed simultaneously.
// Example: Without threading (blocking) public void downloadFiles() { downloadFile1(); // Blocks until complete downloadFile2(); // Waits for file1 to finish downloadFile3(); // Waits for file2 to finish } // Example: With threading (concurrent) public void downloadFilesParallel() { Thread t1 = new Thread(() -> downloadFile1()); Thread t2 = new Thread(() -> downloadFile2()); Thread t3 = new Thread(() -> downloadFile3()); t1.start(); // All files download t2.start(); // simultaneously t3.start(); }
class MyThread extends Thread {
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println("Thread: " + getName() + ", Count: " + i);
try { Thread.sleep(1000); } catch (InterruptedException e) {}
}
}
}
// Usage
MyThread thread1 = new MyThread();
thread1.start();
class MyRunnable implements Runnable {
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println("Runnable: " + Thread.currentThread().getName());
try { Thread.sleep(1000); } catch (InterruptedException e) {}
}
}
}
// Usage
Thread thread2 = new Thread(new MyRunnable());
thread2.start();
Thread thread3 = new Thread(() -> {
for (int i = 0; i < 5; i++) {
System.out.println("Lambda Thread: " + i);
try { Thread.sleep(1000); } catch (InterruptedException e) {}
}
});
thread3.start();
ExecutorService executor = Executors.newFixedThreadPool(3);
executor.submit(() -> {
System.out.println("Task executed by: " + Thread.currentThread().getName());
});
executor.shutdown();
Thread thread = new Thread(() -> {
try {
Thread.sleep(2000); // TIMED_WAITING
synchronized(lock) {
// Could be BLOCKED if lock not available
wait(); // WAITING
}
} catch (InterruptedException e) {
// Handle interruption
}
}); // NEW
thread.start(); // RUNNABLE -> RUNNING -> TERMINATED
Multiple threads accessing shared data simultaneously, leading to unpredictable results.
Two or more threads waiting for each other indefinitely.
A thread is unable to gain access to shared resources and cannot make progress.
Threads are not blocked but constantly changing states in response to others, making no progress.
// Race Condition Example class Counter { private int count = 0; public void increment() { count++; // Not atomic! Can cause race condition } public int getCount() { return count; } } // Deadlock Example Object lock1 = new Object(); Object lock2 = new Object(); Thread t1 = new Thread(() -> { synchronized(lock1) { synchronized(lock2) { /* work */ } } }); Thread t2 = new Thread(() -> { synchronized(lock2) { synchronized(lock1) { /* work */ } // Deadlock! } });
Ensures only one thread can access critical sections at a time.
public synchronized void increment() {
count++; // Thread-safe now
}
// Or using synchronized block
public void increment() {
synchronized(this) {
count++;
}
}
Thread-safe operations without explicit synchronization.
AtomicInteger atomicCounter = new AtomicInteger(0);
public void increment() {
atomicCounter.incrementAndGet(); // Thread-safe atomic operation
}
More flexible than synchronized with additional features.
private final ReentrantLock lock = new ReentrantLock();
public void increment() {
lock.lock();
try {
count++;
} finally {
lock.unlock();
}
}
Every object in Java has an intrinsic lock. Synchronized methods/blocks use this lock.
public class BankAccount {
private double balance;
public synchronized void deposit(double amount) {
balance += amount; // Only one thread can execute this
}
public synchronized void withdraw(double amount) {
if (balance >= amount) {
balance -= amount;
}
}
}
Inter-thread communication using object monitors.
class ProducerConsumer {
private Queue<Integer> queue = new LinkedList<>();
private final int CAPACITY = 5;
public synchronized void produce(int item) throws InterruptedException {
while (queue.size() == CAPACITY) {
wait(); // Release lock and wait
}
queue.offer(item);
notifyAll(); // Notify waiting consumers
}
public synchronized int consume() throws InterruptedException {
while (queue.isEmpty()) {
wait(); // Release lock and wait
}
int item = queue.poll();
notifyAll(); // Notify waiting producers
return item;
}
}
// Semaphore Example Semaphore semaphore = new Semaphore(3); // Allow 3 concurrent access public void accessResource() { try { semaphore.acquire(); // Get permit // Use resource } finally { semaphore.release(); // Return permit } } // CountDownLatch Example CountDownLatch latch = new CountDownLatch(3); // Worker threads new Thread(() -> { // Do work latch.countDown(); // Signal completion }).start(); latch.await(); // Wait for all workers to complete