필요한 자원을 모두 다른 곳에서 확보하고 놓지 않기 때문에 모두가 서로 상대방 자원을 놓기만을 기다리는 상황

락 순서에 의한 데드락

public class LeftRightDeadlock {
    private final Object left = new Object();
    private final Object right = new Object();
 
    public void leftRight() {
        synchronized (left) {
            synchronized (right) {
                doSomething();
            }
        }
    }
 
    public void rightLeft() {
        synchronized (right) {
            synchronized (left) {
                doSomethingElse();
            }
        }
    }
 
    void doSomething() { }
    void doSomethingElse() { }
}

동적인 순서에 의한 데드락

// Warning: deadlock-prone!
public static void transferMoney
(
    Account fromAccount,
    Account toAccount,
    DollarAmount amount
) throws InsufficientFundsException
{
    synchronized (fromAccount) {
        synchronized (toAccount) {
            if (fromAccount.getBalance().compareTo(amount) < 0) {
                throw new InsufficientFundsException();
            } else {
                fromAccount.debit(amount);
                toAccount.credit(amount);
            }
        }
    }
}
transferMoney(myAccount, yourAccount, 10);
transferMoney(yourAccount, myAccount, 20);

결국 서로 다른 순서로 락을 잡는 것과 동일한 효과. System.identityHashCode 를 사용하여 락 순서를 결정하는 방법도 있긴 하지만 데드락의 위험성이 없어진 것은 아님.

리소스 데드락

다른 작업의 실행 결과를 확인해야만 하는 작업이 있다면 스레드 소모성 데드락의 원인이 되기 쉽다.

(자바 병렬 프로그래밍 8.1.1 절 참고)

오픈 호출

특정 메서드를 호출할때 해당 메서드를 호출하는 메서드를 알지 못해야 한다.

락을 전혀 확보하지 않은 상태에서 메서드를 호출하는 것은 오픈호출이라 한다. 만약 호출하는 메서드가 락을 걸고 메서드를 호출할때 호출당하는 메서드에서 또 중복하여 락을 걸 경우 데드락의 위험이 있기 때문이다.

단순히 간편하다는 이유만으로 메서드 전체에 syncronized 를 거는 것은 이래서 위험하다. 필요한 부분만 락을 잡는 다는 것은 병렬 프로그래밍의 기본