StampedLock — 세 가지 모드를 가진 기능 기반 락

StampedLock — 세 가지 모드를 가진 기능 기반 락

StampedLock은 읽기·쓰기 접근을 제어하는 세 가지 모드를 가진 기능 기반(capability-based) 락이에요. StampedLock의 상태는 버전(version)과 모드(mode)로 구성돼요.

출처: Java API Reference

본문

락 획득 메서드는 락 상태에 대한 접근을 제어하는 스탬프(stamp) 를 반환해요. "try" 버전 메서드는 획득 실패를 나타내는 특수 값 0을 반환할 수도 있어요. 락 해제·변환 메서드는 스탬프를 인자로 요구하고, 락 상태와 맞지 않으면 실패해요.

세 가지 모드

Writing (쓰기)writeLock()은 배타 접근을 위해 블로킹하면서, unlockWrite(long)에서 해제하는 데 쓸 스탬프를 반환해요. 쓰기 모드로 잡혀 있으면 읽기 락을 얻을 수 없고 모든 낙관적 읽기 검증이 실패해요.

Reading (읽기)readLock()은 비배타 접근을 위해 블로킹하면서, unlockRead(long)에서 해제하는 데 쓸 스탬프를 반환해요.

Optimistic Reading (낙관적 읽기)tryOptimisticRead()는 락이 쓰기 모드로 잡혀 있지 않을 때만 0이 아닌 스탬프를 반환해요. validate(long)는 주어진 스탬프를 얻은 후 락이 쓰기 모드로 획득되지 않았으면 true를 반환해요. 이 모드는 매우 약한 읽기 락으로 생각할 수 있고, 언제든 쓰기가 깨뜨릴 수 있어요. 짧은 읽기 전용 코드 구간에 쓰면 경쟁을 줄이고 처리량을 높여요. 하지만 본질적으로 깨지기 쉬우므로, 낙관적 읽기 구간은 필드를 읽고 검증 후 나중에 쓰도록 로컬 변수에만 담아야 해요.

이 클래스는 세 모드 간 조건부 변환을 제공하는 메서드도 지원해요. 예를 들어 tryConvertToWriteLock(long)은 (1) 이미 쓰기 모드이거나 (2) 읽기 모드이고 다른 읽기 스레드가 없거나 (3) 낙관적 읽기 모드이고 락이 가능하면 유효한 쓰기 스탬프를 반환해요.

설계 특성

StampedLock은 스레드 안전 컴포넌트 개발을 위한 내부 유틸리티로 설계됐어요. 재진입이 아니므로 잠긴 구간은 재획득을 시도할 수 있는 다른 알 수 없는 메서드를 호출하면 안 돼요. 읽기 락 모드 사용은 연관 코드 구간이 부작용이 없어야 한다는 점에 의존해요. 스탬프는 유한한 표현을 쓰고 암호학적으로 안전하지 않아요(유효 스탬프가 추측될 수 있음). 스탬프 값은 연속 1년 운영 후 재사용될 수 있어요.

Semaphore처럼, 대부분의 Lock 구현과 달리 StampedLock은 소유권 개념이 없어요. 한 스레드에서 획득한 락을 다른 스레드에서 해제·변환할 수 있어요. StampedLock의 스케줄링 정책은 읽기·쓰기를 일관되게 선호하지 않아요. 모든 "try" 메서드는 최선 노력이며 어떤 스케줄링·공정성 정책에도 반드시 따르지 않아요.

여러 락 모드에 걸친 조정 사용을 지원하기 때문에 이 클래스는 Lock이나 ReadWriteLock 인터페이스를 직접 구현하지 않아요. 하지만 asReadLock(), asWriteLock(), asReadWriteLock()로 볼 수 있어요.

생성자

StampedLock() — 처음에 해제된 상태의 새 락을 만들어요.

락 획득 메서드

long writeLock() — 배타적으로 획득하고 필요하면 블로킹해요.

long tryWriteLock() / long tryWriteLock(long time, TimeUnit unit) — 즉시 또는 지정 시간 내에 배타적으로 획득해요.

long writeLockInterruptibly() — 필요하면 블로킹하면서 배타적으로 획득하거나 인터럽트 시 예외를 던져요.

long readLock() — 비배타적으로 획득하고 필요하면 블로킹해요.

long tryReadLock() / long tryReadLock(long time, TimeUnit unit) — 즉시 또는 지정 시간 내에 비배타적으로 획득해요.

long readLockInterruptibly() — 비배타적으로 획득하거나 인터럽트 시 예외를 던져요.

long tryOptimisticRead() — 나중에 검증할 수 있는 스탬프를 반환하거나, 배타적으로 잠겨 있으면 0을 반환해요.

boolean validate(long stamp) — 주어진 스탬프가 발행된 후 락이 배타적으로 획득되지 않았으면 true를 반환해요.

락 해제·변환 메서드

void unlockWrite(long stamp) / void unlockRead(long stamp) / void unlock(long stamp) — 락 상태가 주어진 스탬프와 맞으면 해당 모드의 락을 해제해요. 맞지 않으면 IllegalMonitorStateException을 던져요.

long tryConvertToWriteLock(long stamp) — 원자적으로 쓰기 모드로 업그레이드하려 시도해요.

long tryConvertToReadLock(long stamp) — 원자적으로 읽기 모드로 변환하려 시도해요.

long tryConvertToOptimisticRead(long stamp) — 원자적으로 낙관적 읽기로 변환하려 시도해요.

boolean tryUnlockWrite() / boolean tryUnlockRead() — 스탬프 없이 쓰기/읽기 락을 해제해요. 오류 복구에 유용해요.

상태 확인 메서드

boolean isWriteLocked() — 현재 배타적으로 잡혀 있으면 true를 반환해요.

boolean isReadLocked() — 현재 비배타적으로 잡혀 있으면 true를 반환해요.

static boolean isWriteLockStamp(long stamp) / static boolean isReadLockStamp(long stamp) / static boolean isLockStamp(long stamp) / static boolean isOptimisticReadStamp(long stamp) — 스탬프가 어떤 종류의 락 보유를 나타내는지 판별해요.

int getReadLockCount() — 보유된 읽기 락 수를 조회해요.

String toString() — 이 락과 락 상태를 식별하는 문자열을 반환해요.

뷰 메서드

Lock asReadLock()Lock.lock()readLock()에 매핑된 일반 Lock 뷰를 반환해요. Condition을 지원하지 않아요.

Lock asWriteLock()Lock.lock()writeLock()에 매핑된 일반 Lock 뷰를 반환해요.

ReadWriteLock asReadWriteLock()readLock()asReadLock()에, writeLock()asWriteLock()에 매핑된 ReadWriteLock 뷰를 반환해요.

더 알아보기 (Learn more)