Lock Ordering (Deadlock Avoidance)

How a simple alphabetical rule completely eliminates the possibility of a deadlock.

The idea

A deadlock happens when two threads create a cycle: Thread 1 locks A and waits for B, while Thread 2 locks B and waits for A. If we can mathematically guarantee that a cycle can never form, deadlocks become impossible. We do this by establishing a strict Global Lock Order. For example, we declare a rule: "If you need multiple locks, you must acquire them in alphabetical order." If both threads obey this rule, Thread 2 is forced to ask for Lock A before Lock B. It will wait in line behind Thread 1. No cycle, no deadlock.

Step 1: The Setup. Thread 1 wants to transfer from Account A to B. Thread 2 wants to transfer from B to A.

How it works (Sorting the Locks)

Before writing your core logic, you gather all the resources you need to lock, and you sort them by a unique ID (like Account ID, Database Primary Key, or memory address). You then acquire the locks in that sorted order, every single time.

// GOOD: Deadlock-proof Transfer
function transferMoney(acc1, acc2) {
    // 1. Establish the Global Order (e.g. by Account ID)
    let first = acc1.id < acc2.id ? acc1 : acc2;
    let second = acc1.id < acc2.id ? acc2 : acc1;

    // 2. ALWAYS lock the 'smaller' ID first
    lock(first); 
    lock(second);
    
    // 3. Do work safely!
    acc1.balance -= 100;
    acc2.balance += 100;
    
    unlock(second);
    unlock(first);
}

Cost

Lock ordering has virtually zero performance cost (sorting two or three IDs takes microseconds). The true cost is developer discipline. In large codebases with complex nested function calls, it can be extremely difficult to ensure every engineer acquires locks in the exact same global order. If even one function breaks the rule, the entire system is vulnerable to deadlocks again.

Watch out for