Design a multi-threaded application scenario where avoiding deadlock is critical.

A common scenario where avoiding deadlock is critical is a multi-threaded banking system that processes account transfers concurrently. During a transfer, a thread may need to lock both the source and destination accounts. If different threads acquire these locks in different orders, they can end up waiting indefinitely for each other, causing a deadlock and preventing transactions from completing.

Key Points: • Deadlocks occur when multiple threads hold resources while waiting for other resources locked by other threads. • A common prevention technique is to acquire locks in a consistent order, such as by account ID or resource ID. • Using lock timeouts, minimizing lock scope, and avoiding nested locks can further reduce deadlock risks.

Example: Imagine Thread A transferring money from Account 1 to Account 2 while Thread B transfers money from Account 2 to Account 1. If Thread A locks Account 1 and Thread B locks Account 2 simultaneously, both threads may wait forever for the other lock, causing a deadlock.

Code Example:

class Account {

    private final int accountId;

    public Account(int accountId) {
        this.accountId = accountId;
    }

    public int getAccountId() {
        return accountId;
    }
}

public class TransferService {

    public void transfer(

Account from,

            Account to) {

        Account firstLock =
                from.getAccountId() < to.getAccountId()

? from

                        : to;

        Account secondLock =
                from.getAccountId() < to.getAccountId()

? to

                        : from;

        synchronized (firstLock) {

            synchronized (secondLock) {

                System.out.println(
                        "Transfer Completed");
            }
        }
    }
}

Interview Tip: A concise interview answer is: A banking fund-transfer system is a classic deadlock-prone scenario because transactions often require multiple account locks. I prevent deadlocks by enforcing a consistent lock acquisition order, minimizing lock duration, and using timeout-based locking when appropriate.