Class Design
Multithread
1. Design a class which provides a lock only if there are no possible deadlocks.
In multithreaded systems, deadlocks occur when two or more threads are waiting on each other to release locks, and none can proceed.
Example:
Thread 1 holds Lock A and waits for Lock B.
Thread 2 holds Lock B and waits for Lock A.
Both are now stuck forever.
Task is to design a class that only allows a thread to acquire a lock if it won't create a deadlock.
Approach 1: Lock Ordering
Assign a unique global order (ID) to each lock.
Threads must acquire locks in a specific order (e.g., increasing ID).
This guarantees no cyclic wait — hence no deadlocks.
If all threads follow the same lock acquisition order, they will never form a circular wait.
Two bank accounts, A and B.
Thread 1: Transfers from A to B
Thread 2: Transfers from B to A
If locks are acquired in different orders, deadlock can happen.
BankAccount.java
TransferManager.java
BankTransferSimulation.java
Explanation:
Thread-1 starts:
Compares
"A"vs"B"→ A firstAcquires lock on A
Tries to acquire lock on B
Meanwhile, Thread-2 starts:
Compares
"B"vs"A"→ A still comes firstTries to acquire lock on A, but it's held by Thread-1
So Thread-2 blocks waiting for A
Thread-1 finishes:
Transfers money
Releases B
Releases A
Now Thread-2:
Acquires A (now free)
Acquires B
Transfers money
Releases both
No deadlock! Both transfers finish correctly.
What If We Didn't Use Ordering?
If threads acquired locks in random order (based on from/to):
Thread-1 locks A → waits for B
Thread-2 locks B → waits for A
Deadlock happens: each thread waits forever!
Approach 2: Try-Lock with Timeout & Rollback
When multiple threads need to acquire multiple locks, and acquiring them in different orders, there's a risk of deadlock. This approach tries to acquire each lock with a timeout, and backs off (releases all acquired locks) if it can't acquire all necessary locks within the timeout window.
This strategy helps in detecting potential deadlocks early and avoiding them by not holding onto locks indefinitely.
By backing off and retrying, threads avoid being stuck in a cycle.
Two users trying to transfer money between two bank accounts. Each transfer needs a lock on both source and target account. If two transfers happen at the same time in opposite directions, a deadlock could happen if both threads acquire one lock each and wait for the other.
Account.java
TransferService.java
DeadlockAvoidanceExample.java
Explanation
Step 1: Thread-1 starts
Intention: Transfer ₹300 from A → B
Calls
tryLock()on Account ASuccessfully acquires lock on A
Waits for a small delay (simulating processing)
Calls
tryLock()on Account B
Step 2: While Thread-1 is waiting
Thread-2 starts
Intention: Transfer ₹500 from B → A
Calls
tryLock()on Account BSuccessfully acquires lock on B
Waits for a small delay
Calls
tryLock()on Account A
Step 3: Deadlock would occur…
Thread-1 has lock on A, waiting for B
Thread-2 has lock on B, waiting for A
In traditional lock acquisition (without timeout), this would be a deadlock.
Step 4: But tryLock() avoids this
tryLock(timeout)times out for both threads on second lockEach thread fails to acquire the second lock within timeout
Each thread:
Logs timeout
Releases already held lock
Optionally retries or exits gracefully
Step 5: Outcome
No deadlock occurs
System continues to operate
One or both threads may retry or log failure
2. Design a mechanism to ensure that first is called before second and second is called before third.
The same instance of Foo will be passed to three different threads. ThreadA will call first,
threads will call second, and threadC will call third.
To solve this problem where three threads (ThreadA, ThreadB, and ThreadC) are calling first(), second(), and third() respectively, we need to enforce ordering:
first()must run beforesecond()second()must run beforethird()
Approach: Using CountDownLatch
CountDownLatchWe can use two CountDownLatch objects to control execution order:
One latch to wait for
first()to complete beforesecond()Another latch to wait for
second()to complete beforethird()
Foo.java
FooTest.java
3. Implement multithreaded FizzBuzz with four threads, each thread is responsible for one task:
Thread A: prints
"Fizz"for numbers divisible by 3 but not 5Thread B: prints
"Buzz"for numbers divisible by 5 but not 3Thread C: prints
"FizzBuzz"for numbers divisible by both 3 and 5Thread D: prints the number if it's not divisible by 3 or 5
FizzBuzz.java
FizzBuzzTest.java
Last updated