백엔드 엔지니어 이재혁
[Java] concurrent.locks 본문
synchronized 키워드를 사용하면, 무한 대기 문제와 공정성 문제가 발생할 수 있다. 이를 해결하기 위해 LockSupport를 사용해서 수동으로 동시성 제어를 할 수도 있다.
LockSupport
park(), partNanos(long ns), unpark(Thread thread) 메서드 제공
park()는 스레드를 WAITING 상태로 변경하고, 다른 스레드에서 unpark() 메서드를 사용해 RUNNABLE 상태로 바꿔줄 수 있다. 인터럽트를 사용하고 싶다면, 인터럽트로도 가능하다. 차이점이라면 스레드의 인터럽트 상태가 바뀌는지 안바뀌는지 여부가 다르다.
참고: BLOCKED 상태는 synchronized 키워드만이 만들 수 있는 상태
LockSupport는 BLOCKED 상태를 사용하지 않고 WAITING 상태를 활용해, 무한 대기하지 않는 락 기능을 구현할 수 있다.
ReentrantLock
하지만, LockSupport를 사용해서 Lock을 손수 구현하기에는 너무 할게 많고 어렵다.
그래서 Lock 인터페이스와 그것을 구현한 ReentrantLock 구현체가 있다.
Lock 인터페이스의 메서드
void lock()
인터럽트에 응답하지 않는 락!
(실제로는 인터럽트를 걸면 RUNNABLE 상태로 잠깐 바뀌었다가 바로 다시 WAITING 상태로 돌아감)
void lockInterruptibly()
위 lock() 메서드와 달리 인터럽트를 허용하는 락. InterruptedException을 던지므로 예외를 받아줘야 함.
boolean tryLock()
락 획득을 시도, 즉시 성공 여부를 반환. (자신이 락을 획득하는데 성공하면 true, 실패하면 false)
주의할 점: tryLock() 시점에 lock을 획득할 수 있다면 lock을 바로 획득하므로 lock.lock()을 따로 실행할 필요가 없음
사실 오히려 lock.lock()을 추가로 실행하면 lock이 여러번 걸려서 그만큼 lock을 여러번 풀어줘야 함.
이 점을 인지하지 못하면 데드락 발생
boolean tryLock(long time, TimeUnit unit)
주어진 시간 동안 락 획득을 시도한다. 획득하면 즉시 true 반환. 시간이 다 되도 획득하지 못했다면, false 반환
대기 중 인터럽트 가능. InterruptedException을 던짐.
void unlock()
락을 해제한다. 락을 획득한 스레드가 호출해야 한다.
☆☆☆☆☆ 중요 ☆☆☆☆☆
lock을 걸었으면 반드시 unlock을 해줘야 하기 때문에 try ~ finally 를 사용해서 실행 중에 무슨 일이 발생하던지간에 unlock이 되도록 만들어야 한다.
private final Lock lock = new ReentrantLock(); // 이런식으로 객체에 lock 객체 넣기
lock.lock(); // ReentrantLock 이용하여 lock을 걸기
try {
// 임계 영역 실행
...
} finally { // 무조건 실행되도록 만들기
lock.unlock();
}
위 메서드들을 활용하면, 스레드의 무한 대기 상태 문제를 해결할 수 있다.
ReentrantLock의 공정모드
ReentrantLock은 공정모드를 제공해서 스레드의 실행 순서를 보장할 수 있다. (선착순)
아래와 같이 ReentrantLock 생성자에 true 를 전달하면 된다.
private final Lock lock = new ReentrantLock(true);
자바 1.5에서 등장한 Lock 인터페이스와 ReentrantLock 덕분에 synchronized 의 단점인 무한 대기와 공정성 문제를 극복하고, 또 더욱 유연하고 세밀한 스레드 제어가 가능하게 되었다.
'Java' 카테고리의 다른 글
| [Java] 생산자 소비자 문제 (2) (0) | 2025.05.27 |
|---|---|
| [Java] 생산자 소비자 문제 (0) | 2025.05.26 |
| [Java] synchronized (0) | 2025.05.22 |
| [Java] 메모리 가시성 (0) | 2025.05.22 |
| [Java] Runnable (0) | 2025.05.19 |