concurrent 패키지
- synchronized의 단점을 보완하며 더 유연하고 세밀한 제어가 가능하도록 concurrent 패키지가 추가되었다.
LockSupport
- concurrent 패키지 중 가장 기본이 되는 LockSupport가 있다.
- LockSupport의 대표적인 기능
- park() : 스레드를 WAITING 상태로 변경한다.
- 스레드가 WAITING 상태이기에 interrupt()로 중간에 깨울 수 있다.
- parkNanos(nanos) : 스레드를 나노초 동안만 TIMED_WAITING 상태로 변경한다.
- 지정 시간이 지나면 RUNNABLE 상태로 변경된다.
- 1초 = 1000밀리초(ms), 1밀리초(ms) = 1,000,000나노초(ns)
- unpark(thread) : WAITING 상태의 대상 스레드를 RUNNABLE 상태로 변경한다.
- WAITING 상태의 스레드는 스스로를 깨울 수 없기 때문에 외부에서 unpark()로 깨워줘야 한다.
- park() : 스레드를 WAITING 상태로 변경한다.
- BLOCKED vs WAITING
- WAITING 상태에 특정 시간까지만 대기하는 기능이 TIMED_WAITING으로 둘 다 WAITING으로 묶어서 표현하겠다.
- 인터럽트
- BLOCKED 상태는 인터럽트가 걸려도 대기 상태를 빠져나오지 못한다
- WAITING 상태는 인터럽트가 걸리면 대기 상태를 빠져나와서 RUNNABLE 상태가 된다.
- 용도
- BLOCKED 상태는 synchronized에서 락을 획득하기 위해 대기할 때 사용한다.
- WAITING 상태는 스레드가 특정 조건, 시간동안 대기할 때 발생하는 상태이다.
- join(), park(), wait(), sleep() ... 메소드 호출 시 WAITING 상태가 된다.
- WAITING과 TIMED_WAITING은 서로 짝이 있다.
- join(), join(millis)
- park(), parkNanos(nanos)
- wait(), wait(timeout)
- BLOCEKD와 WAITING 상태 모두 스레드가 대기하며 실행 스케줄링 큐에 들어가지 않기 때문에 CPU 입장에서는 비슷한 상태이다.
- BLOCKED는 synchronized에서만 사용하는 특별한 대기 상태
- WAITING은 범용적으로 활용할 수 있는 대기 상태
Lock & ReentrantLock
- Lock 인터페이스 & ReentrantLock : synchronized와 BLOCKED 상태를 통한 임계 영역 관리 한계를 극복하기 위해 자바에서 Lock 인터페이스와 ReentrantLock 구현체를 제공한다.
- Lock 인터페이스는 동시성 프로그래밍에서 쓰이는 안전한 임계 영역을 위한 락을 구현하는데 사용하며 대표적인 구현체로 ReentrantLock이 있다.
- Lock 인터페이스의 대표적인 기능
- void lock() : 락을 획득하고 다른 스레드가 이미 락을 획득했다면 락이 풀릴 때까지 현재 스레드는 WAITING 상태가 되지만 인터럽트에 응답하지 않는다.
- 여기서 락은 객체 내부의 모니터 락과는 다른 Lock 인터페이스에서 제공하는 기능이다.
- 모니터 락과 BLOCKED 상태는 synchronized에서만 사용된다.
- void lockInterruptibly() : lock()과 기능은 동일하되 대기중 인터럽트가 발생하면 InterruptException 예외가 발생하며 해당 스레드는 락 획득을 포기한다.
- boolean tryLock() : 락 획득을 시도하고 즉시 성공 여부를 반환한다.
- boolean tryLock(time, unit) : 주어진 시간 동안 락 획득을 시도하고 인터럽트가 발생하면 예외가 발생하며 락 획득을 포기한다.
- void unlock() : 락을 해제하며 락 획득을 대기 중인 스레드 중 하나가 락을 획득할 수 있게 된다. 락을 획득한 스레드가 호출해야한다.
- Condition newCondition() : Condition 객체를 생성해 반환한다. Condition 객체는 락과 결합되어 사용되며 스레드가 특정 조건을 기다리거나 신호를 받을 수 있도록 한다.
- Object 클래스의 wait(), notify(), notifyAll()과 유사한 역할을 한다.
- void lock() : 락을 획득하고 다른 스레드가 이미 락을 획득했다면 락이 풀릴 때까지 현재 스레드는 WAITING 상태가 되지만 인터럽트에 응답하지 않는다.
- Lock 인터페이스를 통해 고수준의 동기화 기법을 구현할 수 있으며 synchronized 보다 더 많은 유연성을 제공함으로 무한 대기 문제를 해결하고 특정 시간 동안만 락을 시도하거나 인터럽트 가능한 락을 구현할 때 유용하다.
- ReentrantLock 구현체를 통해 스레드가 공정하게 락을 얻을 수 있는 모드를 제공한다.
- 오래 기다린 스레드가 락을 획득할 수 있도록 보장하는 모드를 지정할 수 있다. (공정 모드)
- 비공정 모드는 기본 모드로 락을 먼저 요청하더라도 락을 먼저 획득한다는 보장이 없다.
- ReentrantLock 비공정 모드
- 락을 요청한 순서대로 획득한다는 보장이 없다.
- 성능 우선 - 락을 획득하는 속도가 빠르다.
- 선점 가능 - 새로운 스레드가 기존 대기 스레드보다 먼저 락을 획득할 수 있다.
- 기아 현상 가능성 - 특정 스레드가 계속해서 락을 획득하지 못할 수 있다.
- 성능은 빠르지만 특정 스레드가 락을 계속해서 획득하지 못할 수 있다.
- ReentrantLock 공정 모드
- 생성자에서 true를 전달함으로 공정 모드로 지정할 수 있다.
- 먼저 대기한 스레드가 먼저 락을 획득하도록 보장한다.
- 공정성 보장 - 대기 큐에서 먼저 대기한 스레드가 락을 먼저 획득한다.
- 기아 현상 방지 - 모든 스레드가 언젠가 락을 획득할 수 있게 보장된다.
- 성능 저하 - 락을 획득하는 속도가 느려진다.
- 락을 획득하는 순서를 보장하는 대신 성능이 저하될 수 있다.
- Lock 인터페이스와 ReentrantLock 구현체를 통해 synchronized의 단점인 공정성과 무한 대기의 문제를 모두 해결할 수 있다.
Lock lock = new ReentrantLock();
public void method(){
//lock() 대신 trylock() 사용 가능
if(!lock.tryLock()){
return false;
}
//lock.lock()
//임계영역
lock.unlock()
}
- synchronized(this) 대신에 ReentrantLock 객체.lock()을 이용해서 락을 건다.
- lock() ~ unlock()까지는 안전한 임계 영역이 된다.
- 임계 영역이 끝나면 락을 반드시 반납해야한다.
- 락을 반납하지 않으면 스레드가 무한 WAITING 상태가 될 수 있기에 unlock()은 무조건 실행되어야 한다.
try ~ finally로 코드를 감싸서 finally에서 unlock()이 무조건 수행되도록 해야한다.- 중간에 예외가 터져도, return을 하더라도 unlock()이 반드시 호출된다.
- lock() 대신 tryLock()을 사용하면 락을 획득할 수 없는 경우 바로 포기함으로 대기하지 않게 할 수 있다.
- 마찬가지로 Lock을 사용하면 volatile을 사용하지 않아도 메모리 가시성 문제가 해결된다.
출처 : [인프런 김영한 실전 자바 - 고급편]
김영한의 실전 자바 - 고급 1편, 멀티스레드와 동시성 강의 | 김영한 - 인프런
김영한 | 멀티스레드와 동시성을 기초부터 실무 레벨까지 깊이있게 학습합니다., 국내 개발 분야 누적 수강생 1위, 제대로 만든 김영한의 실전 자바[사진][임베딩 영상]단순히 자바 문법을 안다?
www.inflearn.com
'Java > [인프런 김영한 실전 자바 - 고급편]' 카테고리의 다른 글
[인프런 김영한 실전 자바 - 고급편] CAS - 동기화와 원자적 연산 (0) | 2024.08.06 |
---|---|
[인프런 김영한 실전 자바 - 고급편] 생산자 소비자 문제 1, 2 (0) | 2024.08.06 |
[인프런 김영한 실전 자바 - 고급편] 동기화 - synchronized (0) | 2024.08.02 |
[인프런 김영한 실전 자바 - 고급편] 메모리 가시성 (0) | 2024.08.02 |
[인프런 김영한 실전 자바 - 고급편] 스레드 제어와 생명 주기 1, 2 (1) | 2024.08.02 |