4주차 Unit 5.3 — ReentrantLock (실무 표준)

Psj·5일 전

F-lab

목록 보기
139/142

Unit 5.3 — ReentrantLock (실무 표준)

F-LAB JAVA · 4주차 · Phase 5 · 정교한 락: LockSupport와 ReentrantLock


📌 학습 목표

이 Unit을 끝내면 다음을 답할 수 있어야 한다.

  • ReentrantLock 의 정의와 위치는?
  • lock() / unlock() 의 사용법은?
  • try-finally 가 필수인 이유는?
  • finally 에서 unlock 안 하면 어떤 사고가?
  • lock() 과 synchronized 의 차이 는?
  • 재진입성 (Reentrant) 의 의미는?
  • 공정성 옵션 (fair) 은?
  • Condition 으로 정교한 대기/통지는?
  • ReentrantLock 의 추가 메서드 들은?

🎯 핵심 한 문장

ReentrantLock 은 java.util.concurrent.locks.Lock 인터페이스의 대표 구현체로, synchronized 와 같은 상호 배제 효과에 더해 타임아웃·인터럽트·공정성 등 정교한 제어를 제공한다.
lock() 으로 락을 획득하고 unlock() 으로 반납하며, 반드시 try-finally 로 감싸 finally 에서 unlock 을 호출 해야 한다 — 임계 영역 중간에 예외나 return 이 발생해도 락이 확실히 반납되도록 하기 위함이다.
finally 에서 unlock 을 깜박하면 락이 영원히 반납되지 않아 다른 스레드들이 무한 대기하는 데드락 이 발생한다 (synchronized 의 자동 반환과 가장 큰 차이).
ReentrantLock 은 이름대로 재진입 가능 하며 (같은 스레드가 락 재획득, 카운트 관리), 생성자에 true 를 주면 공정 모드 (FIFO) 로 동작한다.
Condition 객체로 wait/notify 보다 정교한 조건별 대기/통지가 가능하며 (여러 Condition), 이것이 ReentrantLock 이 "실무 표준" 으로 불리는 이유다.

비유 — 수동 잠금 금고

ReentrantLock = 수동 잠금 금고:

synchronized = 자동문 (자동 잠금/해제):
  - 들어가면 자동 잠김
  - 나오면 자동 해제

ReentrantLock = 수동 금고 (직접 열쇠):
  lock() = 금고 열기 (직접)
  unlock() = 금고 닫기 (직접, 필수!)

try-finally 필수:
  try {
    금고 사용
  } finally {
    금고 닫기 (unlock)   // 예외 나도 닫기
  }

unlock 깜박:
  - 금고 안 닫음
  - 다른 사람 영원히 못 씀 (데드락)

추가 기능 (자동문엔 없음):
  - tryLock: "잠겨있으면 포기"
  - lockInterruptibly: "두드리면 나옴"
  - 공정 모드: "줄 순서"
  - Condition: "특정 신호 대기"

→ ReentrantLock = 수동 락 (강력하지만 try-finally 필수).


🧭 9개 섹션 로드맵

1. ReentrantLock의 정의
2. lock() / unlock() 사용
3. try-finally 필수
4. unlock 누락의 사고
5. lock() vs synchronized
6. 재진입성
7. 공정성 옵션
8. Condition (정교한 대기/통지)
9. 면접 + 자기 점검

1️⃣ ReentrantLock의 정의

1.1 ReentrantLock 이란

ReentrantLock:

  java.util.concurrent.locks.ReentrantLock
  Lock 인터페이스의 대표 구현체.

특징:
  - synchronized 효과 + 추가 기능
  - 명시적 lock/unlock
  - 재진입 가능
  - 공정성 옵션

1.2 Lock 인터페이스

public interface Lock {
    void lock();
    void lockInterruptibly() throws InterruptedException;
    boolean tryLock();
    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
    void unlock();
    Condition newCondition();
}

// ReentrantLock 이 구현

1.3 생성

import java.util.concurrent.locks.ReentrantLock;

// 비공정 (기본)
ReentrantLock lock = new ReentrantLock();

// 공정 모드
ReentrantLock fairLock = new ReentrantLock(true);

1.4 기본 사용

public class Counter {
    private int count = 0;
    private final ReentrantLock lock = new ReentrantLock();
    
    public void increment() {
        lock.lock();   // 획득
        try {
            count++;
        } finally {
            lock.unlock();   // 반납 (필수)
        }
    }
}

1.5 ILIC 의 맥락

@Service
public class ShipmentLockService {
    
    private int processedCount = 0;
    private final ReentrantLock lock = new ReentrantLock();
    
    public void process(Shipment shipment) {
        lock.lock();
        try {
            processedCount++;
            doProcess(shipment);
        } finally {
            lock.unlock();
        }
    }
    
    private void doProcess(Shipment s) { }
}

1.6 자기 점검 답변

ReentrantLock의 정의는?

:
1. 정의:

  • Lock 인터페이스 구현체
  • java.util.concurrent.locks
  1. 특징:

    • synchronized + 추가 기능
    • 명시적 lock/unlock
  2. 생성:

    • new ReentrantLock()
    • true: 공정
  3. 사용:

    • lock() + try-finally

2️⃣ lock() / unlock() 사용

2.1 기본 패턴

ReentrantLock lock = new ReentrantLock();

lock.lock();        // 1. 락 획득
try {
    // 2. 임계 영역
} finally {
    lock.unlock();  // 3. 락 반납 (finally)
}

2.2 lock()

lock():

  락 획득.
  - 락 비어있으면 → 획득 (즉시)
  - 락 있으면 → 대기 (WAITING)

특징:
  - 무한 대기 (lock())
  - 인터럽트 X (lock())

2.3 unlock()

unlock():

  락 반납.
  - 락 보유 스레드만 호출 가능
  - 재진입 카운트 감소
  - 카운트 0 시 완전 반납

주의:
  - 락 없이 unlock → IllegalMonitorStateException

2.4 잘못된 사용

// ❌ try-finally 없음
lock.lock();
count++;   // 예외 시 unlock 안 됨
lock.unlock();
// 예외 발생 시 락 영원히 안 풀림

// ❌ unlock 위치 잘못
lock.lock();
try {
    count++;
    lock.unlock();   // try 안에서 (잘못)
    moreWork();      // 이미 unlock (위험)
} finally {
    // 비어있음
}

2.5 올바른 사용

// ✓ 올바른 패턴
lock.lock();
try {
    count++;
    // 모든 임계 영역
} finally {
    lock.unlock();   // 항상 finally
}

2.6 ILIC 의 맥락

@Service
public class LockUsageExample {
    
    private final ReentrantLock lock = new ReentrantLock();
    private BigDecimal balance = BigDecimal.ZERO;
    
    public void deposit(BigDecimal amount) {
        lock.lock();
        try {
            balance = balance.add(amount);
        } finally {
            lock.unlock();
        }
    }
    
    public BigDecimal withdraw(BigDecimal amount) {
        lock.lock();
        try {
            if (balance.compareTo(amount) >= 0) {
                balance = balance.subtract(amount);
                return amount;
            }
            return BigDecimal.ZERO;
        } finally {
            lock.unlock();   // return 해도 finally 실행
        }
    }
}

2.7 자기 점검 답변

lock() / unlock() 사용은?

:
1. 패턴:

  • lock() → try → finally unlock()
  1. lock():

    • 획득
    • 무한 대기
  2. unlock():

    • 반납
    • finally 에서
  3. 주의:

    • 락 없이 unlock → 예외

3️⃣ try-finally 필수

3.1 왜 필수인가

try-finally 필수 이유:

  임계 영역 중간에:
    - 예외 발생
    - return
    - break/continue

  → unlock 안 되면 락 잔류
  → 다른 스레드 무한 대기 (데드락)

  finally:
    - 어떤 경우에도 실행
    - unlock 보장

3.2 예외 시나리오

// ❌ try-finally 없음
lock.lock();
process();   // 예외 발생!
lock.unlock();   // ★ 실행 안 됨 (예외로 건너뜀)
// 락 영원히 잔류

// ✓ try-finally
lock.lock();
try {
    process();   // 예외 발생
} finally {
    lock.unlock();   // 예외 시에도 실행
}

3.3 return 시나리오

// ❌ return 으로 unlock 누락 가능
public boolean check() {
    lock.lock();
    if (condition) {
        return true;   // ★ unlock 안 됨
    }
    lock.unlock();   // condition false 일 때만
    return false;
}

// ✓ try-finally
public boolean checkSafe() {
    lock.lock();
    try {
        if (condition) {
            return true;   // finally 실행됨
        }
        return false;
    } finally {
        lock.unlock();   // 모든 return 에서
    }
}

3.4 lock() 위치

// ✓ lock() 은 try 밖
lock.lock();   // try 밖
try {
    // ...
} finally {
    lock.unlock();
}

// 이유:
// - lock() 이 예외 던지면 (드물게)
// - try 안이면 unlock 호출 (락 없는데)
// - IllegalMonitorStateException

// lock() 은 try 직전, unlock 은 finally

3.5 시각화

try-finally 보장:

정상:
  lock() → [임계 영역] → finally unlock()

예외:
  lock() → [임계 영역 예외] → finally unlock()
                               ↑ 보장

return:
  lock() → [return] → finally unlock()
                       ↑ 보장

3.6 ILIC 의 맥락

@Service
public class TryFinallyExample {
    
    private final ReentrantLock lock = new ReentrantLock();
    private int stock = 100;
    
    // ✓ try-finally (예외/return 안전)
    public boolean reserve(int quantity) {
        lock.lock();
        try {
            if (stock < quantity) {
                return false;   // return — finally 실행
            }
            stock -= quantity;
            validateStock();   // 예외 가능 — finally 실행
            return true;
        } finally {
            lock.unlock();   // 모든 경우 반납
        }
    }
    
    private void validateStock() {
        if (stock < 0) {
            throw new IllegalStateException("Negative stock");
            // 예외! 하지만 락 반납됨
        }
    }
}

3.7 자기 점검 답변

try-finally가 필수인 이유는?

:
1. 필수:

  • 예외/return/break 시
  • unlock 보장
  1. 예외:

    • try 없으면 unlock 건너뜀
    • 락 잔류
  2. return:

    • finally 가 모든 return 처리
  3. 위치:

    • lock() try 밖
    • unlock() finally

4️⃣ unlock 누락의 사고

4.1 락 잔류

unlock 누락 사고:

  unlock 호출 안 됨:
    - 락 영원히 보유
    - 다른 스레드 무한 대기
    - 데드락

원인:
  - try-finally 없음
  - finally 에 unlock 빠짐
  - 예외/return 경로

4.2 데드락 시나리오

// ❌ unlock 누락
public void process() {
    lock.lock();
    doWork();   // 예외!
    lock.unlock();   // 실행 안 됨
}

// 결과:
// - 이 스레드: 예외로 빠짐 (락 보유한 채)
// - 다른 스레드: lock() 무한 대기
// - 데드락

4.3 진단

# jstack 으로 진단
$ jstack <pid>

# 락 대기 스레드들:
"worker-1" WAITING
  at jdk.internal.misc.Unsafe.park
  - parking to wait for <0x...> (ReentrantLock)
"worker-2" WAITING
  (같은 락 대기)
...

# 락 보유 스레드 (찾기 어려움)
# - 이미 다른 작업 중일 수도
# - 또는 예외로 사라짐

4.4 예방

// ✓ 항상 try-finally
lock.lock();
try {
    // 임계 영역
} finally {
    lock.unlock();
}

// ✓ IDE/린트 도구 활용
// - SonarQube, SpotBugs
// - unlock 누락 경고

// ✓ 코드 리뷰
// - lock 다음 try-finally 확인

4.5 synchronized 와 비교

unlock 누락 위험:

ReentrantLock:
  - 수동 unlock
  - 깜박하면 데드락
  - try-finally 필수

synchronized:
  - 자동 반환
  - 누락 불가능
  - 안전

→ synchronized 가 이 점에서 안전
→ ReentrantLock 은 주의 필요

4.6 ILIC 의 맥락

@Service
public class UnlockMissingProblem {
    
    private final ReentrantLock lock = new ReentrantLock();
    
    // ❌ 사고 — unlock 누락
    public void dangerous(Shipment shipment) {
        lock.lock();
        process(shipment);   // 예외 시 unlock 안 됨
        lock.unlock();
        // 예외 발생 시 락 잔류 → 데드락
    }
    
    // ✓ 안전 — try-finally
    public void safe(Shipment shipment) {
        lock.lock();
        try {
            process(shipment);
        } finally {
            lock.unlock();   // 항상 반납
        }
    }
    
    private void process(Shipment s) {
        if (s == null) throw new IllegalArgumentException();
        // 예외 가능
    }
}

4.7 자기 점검 답변

unlock 누락의 사고는?

:
1. 락 잔류:

  • unlock 안 됨
  • 영원히 보유
  1. 데드락:

    • 다른 스레드 무한 대기
  2. 원인:

    • try-finally 없음
    • 예외/return
  3. 예방:

    • try-finally
    • IDE/린트
    • 코드 리뷰

5️⃣ lock() vs synchronized

5.1 비교

항목synchronizedReentrantLock
반환자동수동 (unlock)
타임아웃XtryLock
인터럽트XlockInterruptibly
공정성X옵션
Conditionwait/notify여러 Condition
안전성높음 (자동)try-finally 필수

5.2 한 문장 차이

lock() vs synchronized 한 문장:

  synchronized 는 자동 반환되는 간단한 동기화이고,
  ReentrantLock 은 명시적 제어가 가능한 유연한 동기화이다.

  synchronized: 간단, 자동, 제한적
  ReentrantLock: 강력, 수동, 유연

5.3 ReentrantLock 의 장점

ReentrantLock 장점:

1. 타임아웃 (tryLock)
2. 인터럽트 (lockInterruptibly)
3. 공정성 (fair)
4. Condition (정교한 대기)
5. tryLock (논블로킹 시도)
6. 락 상태 조회 (isLocked 등)

5.4 synchronized 의 장점

synchronized 장점:

1. 자동 반환 (안전)
2. 간단 (키워드)
3. 가독성
4. JVM 최적화

→ 단순한 경우 충분

5.5 선택

선택:

synchronized:
  - 단순한 동기화
  - 자동 반환 원함

ReentrantLock:
  - 타임아웃/인터럽트
  - 공정성
  - Condition
  - 정교한 제어

권장:
  - 먼저 synchronized
  - 필요 시 ReentrantLock

5.6 ILIC 의 맥락

@Service
public class LockVsSyncChoice {
    
    private int counter = 0;
    
    // synchronized — 단순
    public synchronized void simpleSync() {
        counter++;
    }
    
    // ReentrantLock — 정교
    private final ReentrantLock lock = new ReentrantLock();
    
    public boolean withTimeout() throws InterruptedException {
        if (lock.tryLock(5, TimeUnit.SECONDS)) {   // 타임아웃
            try {
                counter++;
                return true;
            } finally {
                lock.unlock();
            }
        }
        return false;
    }
    
    public void interruptible() throws InterruptedException {
        lock.lockInterruptibly();   // 인터럽트
        try {
            counter++;
        } finally {
            lock.unlock();
        }
    }
}

5.7 자기 점검 답변

lock() vs synchronized 차이는?

:
1. 한 문장:

  • synchronized: 자동, 간단
  • ReentrantLock: 수동, 유연
  1. ReentrantLock 장점:

    • 타임아웃, 인터럽트
    • 공정성, Condition
  2. synchronized 장점:

    • 자동 반환
    • 간단
  3. 선택:

    • 단순: synchronized
    • 정교: ReentrantLock

6️⃣ 재진입성

6.1 재진입 (Reentrant)

재진입 (Reentrant):

  같은 스레드가 이미 가진 락을
  다시 획득 가능.

  "Reentrant" Lock = 재진입 락

효과:
  - 중첩 lock 가능
  - 자기 데드락 방지

6.2 재진입 예시

ReentrantLock lock = new ReentrantLock();

public void outer() {
    lock.lock();   // 카운트 1
    try {
        inner();   // 중첩
    } finally {
        lock.unlock();   // 카운트 0
    }
}

public void inner() {
    lock.lock();   // 카운트 2 (재진입)
    try {
        // ...
    } finally {
        lock.unlock();   // 카운트 1
    }
}

6.3 재진입 카운트

재진입 카운트:

  락 획득마다 카운트++
  반납마다 카운트--
  카운트 0 시 완전 반납

예:
  lock() → 1
  lock() → 2 (재진입)
  unlock() → 1
  unlock() → 0 (완전 반납)

주의:
  - lock 횟수 = unlock 횟수

6.4 lock = unlock 짝

// 재진입 시 lock/unlock 짝 맞춰야
public void method() {
    lock.lock();   // 1
    try {
        lock.lock();   // 2
        try {
            // ...
        } finally {
            lock.unlock();   // 1
        }
    } finally {
        lock.unlock();   // 0
    }
    // lock 2번 = unlock 2번
}

6.5 재진입 없으면

재진입 없는 락:

  같은 스레드가 재획득 시도:
    - 자기 자신 대기
    - 데드락 (self-deadlock)

ReentrantLock:
  - 재진입 가능
  - 같은 스레드 OK
  - 안전

6.6 ILIC 의 맥락

@Service
public class ReentrantExample {
    
    private final ReentrantLock lock = new ReentrantLock();
    
    public void processAll(List<Shipment> shipments) {
        lock.lock();   // 카운트 1
        try {
            for (Shipment s : shipments) {
                processOne(s);   // 중첩 lock
            }
        } finally {
            lock.unlock();   // 카운트 0
        }
    }
    
    public void processOne(Shipment shipment) {
        lock.lock();   // 재진입 (카운트 2 if from processAll)
        try {
            doProcess(shipment);
        } finally {
            lock.unlock();   // 카운트 1
        }
    }
    // 재진입 가능 → 중첩 호출 안전
    
    // 락 상태 조회
    public void checkLockState() {
        log.info("Held by current: {}", lock.isHeldByCurrentThread());
        log.info("Hold count: {}", lock.getHoldCount());   // 재진입 카운트
    }
    
    private void doProcess(Shipment s) { }
}

6.7 자기 점검 답변

재진입성의 의미는?

:
1. 재진입:

  • 같은 스레드 재획득
  • 중첩 lock
  1. 카운트:

    • 획득++ 반납--
    • 0 시 완전 반납
  2. 짝 맞춤:

    • lock 횟수 = unlock 횟수
  3. 효과:

    • self-deadlock 방지

7️⃣ 공정성 옵션

7.1 공정 모드

// 비공정 (기본)
ReentrantLock lock = new ReentrantLock();
ReentrantLock lock2 = new ReentrantLock(false);

// 공정
ReentrantLock fairLock = new ReentrantLock(true);

7.2 공정 vs 비공정

공정 vs 비공정:

공정 (Fair):
  - FIFO 순서
  - 먼저 대기 먼저 획득
  - 기아 방지
  - 성능 ↓

비공정 (Non-fair, 기본):
  - 순서 보장 X
  - 새치기 가능
  - 처리량 ↑
  - 기아 가능

7.3 왜 비공정이 기본

비공정이 기본인 이유:

  성능:
    - 공정성 관리 비용 없음
    - 처리량 ↑
    - 컨텍스트 스위칭 ↓

  대부분:
    - 순서 중요하지 않음
    - 처리량 우선

→ 기본 비공정 (성능)

7.4 공정 모드 비용

공정 모드 비용:

  - 대기 순서 관리 (큐)
  - 새치기 방지
  - 처리량 ↓ (순서 강제)

언제 공정:
  - 순서 중요
  - 기아 방지 필수
  - 처리량보다 공평성

7.5 ILIC 의 맥락

@Service
public class FairnessOption {
    
    // 비공정 (기본, 성능)
    private final ReentrantLock nonFairLock = new ReentrantLock();
    
    public void processNonFair(Shipment shipment) {
        nonFairLock.lock();   // 순서 보장 X (빠름)
        try {
            doProcess(shipment);
        } finally {
            nonFairLock.unlock();
        }
    }
    
    // 공정 (순서 중요 시)
    private final ReentrantLock fairLock = new ReentrantLock(true);
    
    public void processFair(Shipment shipment) {
        fairLock.lock();   // FIFO (먼저 온 순서)
        try {
            doProcess(shipment);
            // 모든 shipment 공평하게 (기아 방지)
        } finally {
            fairLock.unlock();
        }
    }
    
    private void doProcess(Shipment s) { }
}

7.6 자기 점검 답변

공정성 옵션은?

:
1. 공정 모드:

  • new ReentrantLock(true)
  1. 공정 vs 비공정:

    • 공정: FIFO, 기아 방지, 느림
    • 비공정: 새치기, 빠름
  2. 기본:

    • 비공정 (성능)
  3. 공정 사용:

    • 순서 중요
    • 기아 방지

8️⃣ Condition (정교한 대기/통지)

8.1 Condition 이란

Condition:

  ReentrantLock 의 대기/통지 메커니즘.
  wait/notify 의 발전된 형태.

생성:
  Condition cond = lock.newCondition();

메서드:
  - await(): 대기 (wait 유사)
  - signal(): 하나 통지 (notify 유사)
  - signalAll(): 모두 통지 (notifyAll 유사)

8.2 사용

ReentrantLock lock = new ReentrantLock();
Condition notEmpty = lock.newCondition();

public Object take() throws InterruptedException {
    lock.lock();
    try {
        while (isEmpty()) {
            notEmpty.await();   // 대기 (락 반납)
        }
        return remove();
    } finally {
        lock.unlock();
    }
}

public void put(Object item) {
    lock.lock();
    try {
        add(item);
        notEmpty.signal();   // 통지
    } finally {
        lock.unlock();
    }
}

8.3 여러 Condition

// wait/notify 는 조건 1개
// Condition 은 여러 개 가능

ReentrantLock lock = new ReentrantLock();
Condition notFull = lock.newCondition();    // 가득 안 참
Condition notEmpty = lock.newCondition();   // 비지 않음

// 생산자: notFull 대기, notEmpty 통지
// 소비자: notEmpty 대기, notFull 통지

// → 정확한 조건별 대기/통지
// → 불필요한 깨어남 ↓

8.4 Condition vs wait/notify

Condition vs wait/notify:

wait/notify:
  - synchronized 와
  - 조건 1개
  - notifyAll 로 모두 깨움 (비효율)

Condition:
  - ReentrantLock 과
  - 여러 조건
  - 조건별 정확한 통지

→ Condition 이 더 정교

8.5 생산자-소비자 예시

// 생산자-소비자 (Condition, Phase 6 미리보기)
public class BoundedBuffer<T> {
    private final ReentrantLock lock = new ReentrantLock();
    private final Condition notFull = lock.newCondition();
    private final Condition notEmpty = lock.newCondition();
    private final Object[] items;
    private int count, putIdx, takeIdx;
    
    public BoundedBuffer(int size) {
        items = new Object[size];
    }
    
    public void put(T item) throws InterruptedException {
        lock.lock();
        try {
            while (count == items.length) {
                notFull.await();   // 가득 차면 대기
            }
            items[putIdx] = item;
            putIdx = (putIdx + 1) % items.length;
            count++;
            notEmpty.signal();   // 소비자 통지
        } finally {
            lock.unlock();
        }
    }
    
    @SuppressWarnings("unchecked")
    public T take() throws InterruptedException {
        lock.lock();
        try {
            while (count == 0) {
                notEmpty.await();   // 비면 대기
            }
            T item = (T) items[takeIdx];
            takeIdx = (takeIdx + 1) % items.length;
            count--;
            notFull.signal();   // 생산자 통지
            return item;
        } finally {
            lock.unlock();
        }
    }
}

8.6 ILIC 의 맥락

@Service
public class ShipmentQueueWithCondition {
    
    private final ReentrantLock lock = new ReentrantLock();
    private final Condition notEmpty = lock.newCondition();
    private final Queue<Shipment> queue = new LinkedList<>();
    
    // 소비자
    public Shipment consume() throws InterruptedException {
        lock.lock();
        try {
            while (queue.isEmpty()) {
                notEmpty.await();   // 비면 대기
            }
            return queue.poll();
        } finally {
            lock.unlock();
        }
    }
    
    // 생산자
    public void produce(Shipment shipment) {
        lock.lock();
        try {
            queue.offer(shipment);
            notEmpty.signal();   // 소비자 깨움
        } finally {
            lock.unlock();
        }
    }
    
    // 실무: BlockingQueue 권장 (이미 구현됨)
}

8.7 자기 점검 답변

Condition으로 정교한 대기/통지는?

:
1. Condition:

  • ReentrantLock 의 대기/통지
  • lock.newCondition()
  1. 메서드:

    • await (대기)
    • signal/signalAll (통지)
  2. 여러 Condition:

    • 조건별 대기/통지
    • wait/notify 는 1개
  3. 장점:

    • 정확한 통지
    • 불필요 깨어남 ↓

9️⃣ 면접 + 자기 점검

9.1 면접 단골 질문 매핑

Q핵심 답변
ReentrantLock?Lock 구현체, 정교한 제어
lock/unlock?명시적 획득/반납
try-finally 필수?예외/return 시 반납
unlock 누락?데드락
lock vs sync?수동/유연 vs 자동/간단
재진입성?같은 스레드 재획득
공정성?new ReentrantLock(true)
Condition?정교한 대기/통지
Condition vs wait?여러 조건
락 상태 조회?isLocked, getHoldCount

9.2 자기 점검 체크리스트

ReentrantLock

  • 정의
  • 생성
  • 사용

lock/unlock

  • 패턴
  • 주의

try-finally

  • 필수 이유
  • lock 위치

unlock 누락

  • 데드락
  • 예방

vs synchronized

  • 비교
  • 선택

재진입

  • 카운트
  • 짝 맞춤

공정성

  • 옵션
  • 트레이드오프

Condition

  • await/signal
  • 여러 조건

9.3 추가 심화 질문

Q1: ReentrantLock 의 추가 메서드?

답:

  • isLocked(): 락 여부
  • isHeldByCurrentThread(): 현재 스레드 보유
  • getHoldCount(): 재진입 카운트
  • getQueueLength(): 대기 수
  • 디버깅/모니터링

Q2: ReadWriteLock?

답:

  • ReentrantReadWriteLock
  • readLock() / writeLock()
  • 읽기는 공유 (동시)
  • 쓰기는 배타
  • 읽기 많으면 효율

Q3: lock.newCondition() 여러 개 이점?

답:

  • 조건별 대기 큐 분리
  • 정확한 통지 (signal)
  • notifyAll 비효율 회피
  • 생산자/소비자 분리

Q4: ReentrantLock 의 내부?

답:

  • AQS 기반
  • state (재진입 카운트)
  • 대기 큐
  • LockSupport.park/unpark

Q5: StampedLock vs ReentrantReadWriteLock?

답:

  • StampedLock: 낙관적 읽기 (lock 없이)
  • 읽기 충돌 적으면 빠름
  • 재진입 X
  • ReentrantReadWriteLock: 재진입 O

🎯 핵심 요약 — 3줄 정리

1. ReentrantLock

  • Lock 구현체, 정교한 제어
  • lock() + try-finally + unlock()

2. try-finally 필수

  • 예외/return 시 unlock 보장
  • 누락하면 데드락 (synchronized 와 차이)

3. 추가 기능

  • 타임아웃, 인터럽트, 공정성
  • 재진입 (카운트)
  • Condition (정교한 대기/통지)

📚 다음으로...

Unit 5.4 — tryLock()으로 데드락 회피 (★ 마스터)

이번 Unit에서 ReentrantLock 을 봤다면, 다음은 tryLock 데드락 회피 (★ 마스터).

  • tryLock() / tryLock(time, unit)
  • 데드락 회피 시나리오
  • 락 순서와 데드락
  • 마스터 Unit (50문항)

Phase 5 진행 상황

🚀 Phase 5 — 정교한 락: LockSupport와 ReentrantLock
  ✅ Unit 5.1 synchronized의 한계 정리
  ✅ Unit 5.2 LockSupport
  ✅ Unit 5.3 ReentrantLock ← 여기
  ⏭ Unit 5.4 tryLock (★ 마스터) — Phase 5 완주

4주차 누적 진행

✅ Phase 1~4 (17 Unit, 1차 정점 완료)
🚀 Phase 5 — Lock 도구 (3/4 진행)

총: 20/35 Unit
profile
Software Developer

0개의 댓글