뮤텍스 락

공유 자원에 동시에 하나의 스레드만 접근할 수 있도록 보장하는 상호 배제(Mutual Exclusion) 동기화 메커니즘입니다.

핵심 원리

뮤텍스 = 자물쇠

스레드 1: 락 획득 → 작업 중 → 락 해제
스레드 2: 락 획득 시도 → 대기 → 락 해제 후 획득 → 작업
스레드 3: 락 획득 시도 → 대기 → ...

→ 공유 자원에 항상 1개 스레드만 접근

뮤텍스가 없을 때 문제 (Race Condition)

// 잔액 출금 - 동시 접근 시 문제 발생
int balance = 1000;

// 스레드 1, 2가 동시에 실행되면?
// 스레드 1: balance 읽기(1000) → 계산(1000-500=500)
// 스레드 2: balance 읽기(1000) → 계산(1000-500=500)
// 스레드 1: balance = 500 저장
// 스레드 2: balance = 500 저장  ← 500이 두 번 출금됐는데 잔액이 500!
balance -= 500;

Java에서 뮤텍스 구현

// 1. synchronized 키워드
class BankAccount {
    private int balance = 1000;

    synchronized void withdraw(int amount) { // 메서드 단위 락
        if (balance >= amount)
            balance -= amount;
    }
}

// 2. ReentrantLock (명시적 락)
class BankAccount {
    private int balance = 1000;
    private final Lock lock = new ReentrantLock();

    void withdraw(int amount) {
        lock.lock();            // 락 획득
        try {
            if (balance >= amount)
                balance -= amount;
        } finally {
            lock.unlock();      // 반드시 해제 (finally 필수!)
        }
    }
}

synchronized vs ReentrantLock

항목synchronizedReentrantLock
락 획득 실패 시무한 대기tryLock()으로 타임아웃 가능
락 해제자동수동 (finally 필수)
공정성 설정불가가능 (new ReentrantLock(true))
조건 변수wait/notifyCondition 객체
코드 복잡도단순 O복잡

뮤텍스 vs 세마포어

항목뮤텍스세마포어
접근 허용 수1개 스레드N개 스레드
소유권락 획득한 스레드만 해제누구나 해제 가능
용도단일 자원 보호자원 개수 제한
예시DB 커넥션 1개DB 커넥션 풀 10개

주의사항: 데드락

스레드 1: A 락 획득 → B 락 대기
스레드 2: B 락 획득 → A 락 대기
→ 서로 무한 대기 = 데드락 발생!
// 해결: 항상 동일한 순서로 락 획득
void transfer(Account from, Account to) {
    Account first  = from.id < to.id ? from : to;  // 항상 id 작은 것 먼저
    Account second = from.id < to.id ? to : from;

    synchronized (first) {
        synchronized (second) {
            // 이체 로직
        }
    }
}

뮤텍스는 강력하지만 잘못 사용하면 데드락, 성능 저하를 유발합니다. 락의 범위는 최대한 좁게 유지하는 것이 중요합니다.

CSLOG에서 보기