일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- django-crontab
- @Header
- sql-mappler
- rainbow table
- AOP
- Spring
- FunctionalInterface
- ReflectUtils
- 문자열 불변성
- 운영체제
- SystemCall
- none이미지
- Thread Library
- OS
- Process
- 프로세스
- custom annotation
- hiberbate
- task_struct
- 문자열 리터럴
- 도커
- java.util.function
- Thread Multiplexing
- spring-data-jpa
- 쓰레드 라이브러리
- functional interface
- python-socketio
- 함수형 인터페이스
- 롬복주의점
- strict stubbing
- Today
- Total
JH's Develog
[JAVA] 자바 쓰레드 동기화(2) - ReentrantLock과 Condition 본문
저번 포스팅에 이어서 java.util.concurrent.locks 패키지의 lock 클래스 중 ReentrantLock 클래스를 이용하여 쓰레드를 동기화 하는 방법을 알아보겠습니다.
ReentrantLock이란
ReentrantLock은 가장 일반적인 lock이며, synchronized 블럭의 wait() & notify() 처럼 await() & signal()을 이용해 특정 조건에서 lock을 풀고 나중에 다시 lock을 얻어 이후의 작업을 수행할 수 있습니다.
synchronized 블럭은 자동으로 lock이 잠기고 풀리기 때문에 편리하지만, ReentrantLock 클래스를 이용하면 다양한 고급기능을 사용할 수 있습니다.
- Lock polling을 지원한다.
- 코드가 단일 블록 형태를 넘어서는 경우 사용 가능 하다.
- 타임 아웃을 지정할 수 있다.
- Condition을 적용해서 대기 중인 쓰레드를 선별적으로 깨울 수 있다.
- lock 획득을 위해 waiting pool에 있는 쓰레드에게 인터럽트를 걸 수 있다.
즉, 위의 기능이 필요할 때 synchronized 블럭 대신 ReentrantLock을 적용하면 됩니다.
사용법
//Constructor
ReentrantLock()
ReentrantLock(boolean fair)
ReentrantLock은 두 개의 생성자를 가지고 있으며, fair를 true로 주면 가장 오래 기다린 쓰레드가 lock을 얻을 수 있도록 공정하게 처리합니다.
단, 공정하게 처리하려면 어떤 쓰레드가 가장 오래 기다렸는지 확인하는 과정이 필요하므로 성능은 떨어집니다.
//Method
void lock() // lock 잠금
void unlock() // lock 해제
boolean isLocked() // lock이 잠겼는지 확인
boolean tryLock() // lock polling
boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException
자동으로 lock의 잠금과 해제가 관리되는 synchronized 블럭과는 다르게, 수동으로(명시적으로) lock을 잠그고 해제 합니다.
일반적인 lock()은 lock을 얻을 때 까지 쓰레드를 블락시키므로 context swtich에 따른 overhead가 발생할 수 있는데, Critical Section의 수행시간이 매우 짧을 경우에는 tryLock()을 통한 Lock polling(SpinLock)을 통해 효율적인 locking이 가능합니다.
tryLock()에 시간을 설정하면, 지정된 시간 동안 Lock을 얻지 못한 경우 다시 작업을 시도할 것인지 포기할 것인지 결정할 수 있습니다.
//기본적인 사용법
class TestClass{
private ReentrantLock lock = new ReentrantLock(); // Lock 생성
public testMethod(){
lock.lock();
try{
//Critical Section
} finally {
lock.unlock();
}
}
}
Condition
synchronized의 wait() & notify()는 쓰레드의 종류를 구분하지 않고 공유 객체의 waiting pool에 같이 몰아 넣어 선별적인 통지가 불가능 했지만,
ReentrantLock과 Condition을 사용하면 쓰레드의 종류에 따라 구분된 waiting pool에서 따로 기다리도록 하여 선별적인 통지를 가능하게 합니다.
private ReentrantLock lock = new ReentrantLock(); // lock 생성
// lock으로 Condition 생성
private Condition forTask1 = lock.newCondition();
private Condition forTask2 = 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() |
'JAVA' 카테고리의 다른 글
[JAVA] Object level lock vs Class level lock (0) | 2022.07.05 |
---|---|
[JAVA] 자바 쓰레드 동기화(1) - synchronized, wait()/notify() (0) | 2022.07.05 |
[JAVA] 문자열 리터럴이 불변인 이유 (Why String is immutable?) (0) | 2022.01.14 |
[JAVA] 함수형 인터페이스 (Functional Interface) (0) | 2022.01.03 |
[JAVA] 람다식 Lambda Expression (0) | 2022.01.02 |