Lock과 Condition을 이용한 동기화
synchronized를 사용하면 자동으로 lock이 잠기고 풀리는 편리함이 있지만 때로는 같은 메서드 내에서만 lock을 걸수 있다는 제약이 불편하기도 하다. 그럴땐 lock클래스를 사용한다.
ReentrantLock
특정 조건에서 lock을 풀고 나중에 다시 lock을 얻고 임계영역으로 들어와서 이후의 작업을 수행할 수 있다.
배타적인 lock으로, 무조건 lock이 있어야만 임계영역의 코드를 수행할 수 있다.
매개변수에 true를 주면 lock이 풀렸을때 가장 오래 기다린 쓰레드가 lock을 획득할 수 있게 처리한다.
(그러나 이렇게 처리하려면 어떤 쓰레드가 가장 오래 기다렸는지 확인해야 되기때문에 성능이 떨어진다)
ReentrantReadWriteLock
읽기를 위한 lock과 쓰기를 위한 lock을 제공한다.
읽기 lock이 걸려있으면, 다른 쓰레드가 읽기 lock을 중복해서 걸고 읽기를 수행할 수 있다. (읽기는 내용을 변경하지 않으므로 동시에 여러 쓰레드가 읽어도 문제가 되지 않는다.) 그러나 읽기 lock이 걸린 상태에서 쓰기 lock을 거는 것은 허용되지 않는다 (반대의 경우도 마찬가지)
StampedLock
lcok을 걸거나 해지할 때 스탬프(long타입의 정수값)를 사용하며, 읽기와 쓰기를 위한 lock외에 낙관적 읽기 lock (optimistic reading lock)이 추가된 것이다.
읽기 lock이 걸려있을때 쓰기 lock을 얻기 위해 읽기 lock이 풀릴때까지 기다려야 하지만, 낙관적 읽기 lock은 쓰기 lock에 의해 바로 풀린다. 만약 낙관적 읽기에 실패하면 읽기 lock을 얻어서 다시 읽어와야 한다.
(무조건 읽기 lock을 걸지 않고, 쓰기와 읽기가 충돌할 때만 쓰기가 끝난 후에 읽기 lock을 거는것)
lock()은 lock을 얻을 때까지 쓰레드를 block시키므로 쓰레드의 응답성이 나빠질수 있다.
반면에 tryLock()이라는 메서드는 다른 쓰레드에 의해 lock이 걸려있으면 lock을 얻으려고 기다리지 않는다.
또는 지정된 시간만큼만 기다린다.
ReentrantLock과 Condition
wait()와 notify()를 사용할때는 쓰레드의 종류를 구분해서 통지하지 못한다는 단점이 있는데, Condition은 이 문제점을 해결할 수 있다.
wait()와 notify()로 쓰레드의 종류를 구분하지 않고, 공유 객체의 waitting pool에 같이 몰아넣는 대신, 쓰레드의 종류에 맞는 Condition을 만들어서 각각의 waitting pool에서 따로 기다리도록 한다.
private ReentrantLock lock = new RenntrantLock(); //lock을 생성
// lock으로 condition을 생성
private Condition forA = lock.newCondition();
private Condition forB = lock.newCondition();
두개의 Condition을 생성하여 wait()와 notify()대신 Condition의 await()와 signal()을 사용한다.
Object | Condition |
void wait() | void await() void awaitUninterruptibly() |
void wait(long timeout) | boolean await(long time, TimeUnit unit) long awaitNanos(long nanosTimeout) boolean awaitUntil(Date deadline) |
void notify() | void signal() |
void notifyAll() | void signalAll() |
condition을 사용함으로써 대기와 통지의 대상을 명확히 구분할 수 있다.
'Language > Java' 카테고리의 다른 글
14. java.util.function 패키지 (0) | 2021.08.04 |
---|---|
13. 람다(Lambda) (0) | 2021.08.04 |
12.3 쓰레드(Thread) - Synchronized를 이용한 동기화 (0) | 2021.07.29 |
12.2 쓰레드(Thread) - 실행 제어 (0) | 2021.07.28 |
12.1 쓰레드 (Thread) - 구현 (0) | 2021.07.28 |