π½οΈ Dining Philosophers Problem
π§ Problem Statement
Section titled βπ§ Problem StatementβThe Dining Philosophers problem is a classic example in concurrency and synchronization. It demonstrates how improper resource management can lead to deadlock and starvation in a multithreaded environment.
πͺ Scenario
Section titled βπͺ Scenarioβ- Five philosophers sit at a round table.
- Each philosopher alternates between:
- π§ Thinking
- π Eating (requires 2 forks: one on the left and one on the right)
- There are exactly 5 forks β one between each pair of philosophers.
β Constraints
Section titled ββ Constraintsβ- A philosopher needs both the left and right fork to eat.
- Only one philosopher can use a fork at any time.
- Must avoid:
- β Deadlock (where everyone grabs one fork and waits forever)
- β Starvation (where someone never gets to eat)
π₯ Input / Output
Section titled βπ₯ Input / OutputβInput:
- 5 philosophers (threads)
- 5 forks (shared resources)
- Infinite loop of thinking and eating
Output:
- Console logs showing philosophers thinking and eating
- No deadlock or starvation should occur
π‘ Intuition About Solving This Problem
Section titled βπ‘ Intuition About Solving This ProblemβThe key insight is that if all 5 philosophers try to eat simultaneously, they can create a deadlock by each holding one fork and waiting for another. The solution is to limit the number of philosophers who can attempt to eat at the same time, ensuring that at least one fork remains available.
π Steps to Take to Solve
Section titled βπ Steps to Take to Solveβ- Identify the shared resources: 5 forks
- Recognize the deadlock condition: All philosophers holding one fork each
- Use a semaphore to limit concurrent access: Allow only 4 philosophers to attempt eating
- Implement proper resource acquisition order: Acquire both forks before eating
- Ensure proper resource release: Release both forks after eating
- Handle the semaphore: Acquire before eating, release after eating
β οΈ Edge Cases to Consider
Section titled ββ οΈ Edge Cases to Considerβ- Deadlock: All philosophers grab left fork simultaneously
- Starvation: Some philosophers might never get both forks
- Resource exhaustion: All forks being held by different philosophers
- Thread interruption: Handling InterruptedException properly
- Uneven distribution: Some philosophers eating more than others
π» Code (with comments)
Section titled βπ» Code (with comments)βimport java.util.concurrent.Semaphore;import java.util.Random;
public class DiningPhilosophers {
private static final Random random = new Random(); private final Semaphore[] forks = new Semaphore[5]; private final Semaphore maxDiners = new Semaphore(4); // Allow only 4 at a time
public DiningPhilosophers() { for (int i = 0; i < 5; i++) { forks[i] = new Semaphore(1); } }
public void lifecycleOfPhilosopher(int id) throws InterruptedException { while (true) { think(id); eat(id); } }
private void think(int id) throws InterruptedException { System.out.println("π§ Philosopher " + id + " is thinking."); Thread.sleep(random.nextInt(500)); }
private void eat(int id) throws InterruptedException { maxDiners.acquire(); // Prevent deadlock by limiting concurrent access
forks[id].acquire(); // Left fork forks[(id + 1) % 5].acquire(); // Right fork
System.out.println("π Philosopher " + id + " is eating."); Thread.sleep(random.nextInt(500));
forks[id].release(); forks[(id + 1) % 5].release();
maxDiners.release(); // Allow others to try eating }
public static void main(String[] args) { DiningPhilosophers dp = new DiningPhilosophers();
for (int i = 0; i < 5; i++) { final int philosopherId = i; new Thread(() -> { try { dp.lifecycleOfPhilosopher(philosopherId); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } }, "Philosopher-" + i).start(); } }}π Dry Run Example
Section titled βπ Dry Run ExampleβInitial State:
- All forks are available (semaphore count = 1)
- maxDiners semaphore count = 4
- All philosophers are thinking
Step 1: Philosopher 0 wants to eat
- maxDiners.acquire() β count becomes 3
- Acquires fork 0 (left)
- Acquires fork 1 (right)
- Starts eating
Step 2: Philosopher 1 wants to eat
- maxDiners.acquire() β count becomes 2
- Tries to acquire fork 1 β blocked (Philosopher 0 has it)
- Waits for fork 1
Step 3: Philosopher 0 finishes eating
- Releases fork 0 and fork 1
- maxDiners.release() β count becomes 3
- Philosopher 1 can now acquire both forks
Result: Deadlock avoided because only 4 philosophers can attempt eating simultaneously.
β±οΈ Time Complexity / Space Complexity
Section titled ββ±οΈ Time Complexity / Space ComplexityβTime Complexity:
- Thinking phase: O(1) per philosopher
- Eating phase: O(1) per philosopher
- Overall: O(n) where n is the number of philosophers
Space Complexity:
- Forks array: O(n) where n is the number of philosophers
- Semaphores: O(n) for forks + O(1) for maxDiners
- Total: O(n)
π Key Challenges
Section titled βπ Key Challengesβ| Challenge | Description |
|---|---|
| π Deadlock | All philosophers grab left fork and wait for right β no one eats |
| π Starvation | Some philosophers might never get forks |
| π§΅ Concurrency | Multiple threads share limited forks |
β Solution: Limit Entry Using Semaphore
Section titled ββ Solution: Limit Entry Using Semaphoreβπ‘ Idea
Section titled βπ‘ IdeaβUse a Semaphore (maxDiners) to allow only 4 philosophers to try eating at a time.
- Ensures at least one fork is free β avoids deadlock.
- Simple and elegant solution using basic concurrency tools.
π Why Does This Work?
Section titled βπ Why Does This Work?β- π½οΈ At most 4 philosophers can try to eat β one fork always free.
- π Forks are released after eating β others can eat too.
- π Fair and deadlock-free solution using simple semaphores.
π©βπ¬ Real-World Analogy
Section titled βπ©βπ¬ Real-World AnalogyβThink of 5 people trying to pick up 2 shared chopsticks to eat. If everyone grabs one chopstick and waits, no one eats.
By letting only 4 people try to eat, we ensure:
- At least one full set of chopsticks is always available
- No one gets stuck waiting forever
π‘ Pro Tips for Interviews
Section titled βπ‘ Pro Tips for Interviewsβ- Use Semaphore or Lock for concurrency.
- Avoid symmetric resource grabbing (e.g. always grabbing left first).
- Discuss fairness and starvation explicitly.
- Mention alternative strategies: odd philosophers pick left then right, evens do the opposite.
β Summary
Section titled ββ Summaryβ| β Feature | Covered |
|---|---|
| Deadlock-free | β Yes |
| Starvation-free | β οΈ Partially |
| Simple and scalable | β Yes |
| Realistic | β Yes |