강의 메모 - CyclicBarrier #
개요 #
- CyclicBarrier 는 공통된 장벽 지점에 도달할 때까지 일련의 스레드가 서로 기다리도록 하는 동기화 보조 도구이다
- 각 스레드끼리 cycleBarrier을 공유하고 각각 쓰레드에서 await()을 호출해야한다.
- countDownLatch는 작업 기준이라면, CyclicBarrier는 쓰레드 기준
- CyclicBarrier 는 대기 중인 스레드가 해제된 후에 재 사용할 수 있기 때문에 순환 장벽이라고 부른다
- CyclicBarrier는 옵션으로 Runnable 명령을 지원하는데 이 명령은 마지막 스레드가 도착한 후에 각 장벽 지점마다 한 번씩 실행되는 장벽액션(barrierAction) 역할을 수행한다
- 이 Runnable 은 스레드가 장벽 이후 실행을 계속하기 전에 공유 상태를 업데이트하는 데 유용하다
- 각 하나의 쓰레드가 await()을 호출해야함
- 각 쓰레드가 await()을 호출하게 되면 -1씩 되어 0이 되는 시점이 있다.
- count == 0이 되면 옵션으로 설정했을때 Runnable (장벽 액션) 을 수행시킬 수 있다. (현재 쓰레드가 수행 : 마지막 await()한 스레드)
- 모든 장벽이 해제되기 전에 수행
- 모든 스레드가 해제되기 직전에 수행
- 모든 스레드가 해제되면 장벽 재사용 가능
- 또다시 await()을 통해서 CyclicBarrier의 재사용이 가능해진다.
사용 용도 #
- 여러 스레드가 병렬로 작업을 수행하다가 특정 단계에 도달하거나 모든 스레드가 특정 작업을 완료하고 모이는 지점에서 사용된다. 예를 들어 병렬 계산 작업 중 중간 결과를 모두 계산한 후에 다음 단계로 진행하기 위해 스레드들이 모이는 경우에 유용하다
- 고정된 수의 스레드가 동시에 특정 작업을 수행하고 모든 스레드가 작업을 완료하고 모이는 시점에서 다음 단계를 진행할 때 사용된다. 즉 여러 스레드가 협력하여 작업을 나누고 동기화하는 데에 적합하다
CyclicBarrier #
// 주어진 수의 파티(스레드)가 CyclicBarrier 에서 await()을 호출하는 경우에 작동하며 CyclicBarrier 가 작동될 때 마지막으로 CyclicBarrier 에 진입한 스레드에 의해
수행되는 장벽 액션을 실행할 새로운 CyclicBarrier를 생성한다
CyclicBarrier(int parties, Runnable barrierAction)
// 이 장벽에서 모든 파티가 await 를 호출할 때까지 기다리며 현재 스레드가 마지막으로 도착한 것이 아닌 경우 다음 중 하나가 발생할 때까지 대기 상태에 있다
1) 마지막 스레드가 도착함
2) 다른 스레드가 현재 스레드를 인터럽트 함
3) 다른 스레드가 다른 대기 중인 스레드 중 하나를 인터럽트 함
4) 다른 스레드가 장벽 대기 중에 타임아웃 됨
5) 다른 스레드가 이 장벽에 대해 reset 을 호출함
// 메서드 진입 시 인터럽트 상태가 설정되거나 또는 대기 중인 동안 인터럽트 되면 InterruptedException이 throw 되며 현재 스레드의 인터럽트 상태는 초기화된다
// 어떤 스레드가 대기 중일 때 장벽이 리셋되거나 장벽이 끊어진 경우 또는 await가 호출될 때 장벽이 깨진 경우에는 BrokenBarrierException이 발생한다
// 어떤 스레드가 대기 중일 때 인터럽트가 발생하면 다른 대기 중인 스레드도 모두 BrokenBarrierException 을 던지고 장벽이 깨진 상태로 전환된다
// 만약 현재 스레드가 마지막으로 도착한 스레드이고 장벽 액션이 제공된 경우 현재 스레드가 해당 액션을 실행한다
// 장벽 액션 중에 예외가 발생하면 해당 예외가 현재 스레드에서 전파되고 장벽은 깨진 상태로 전환된다
int await() throws InterruptedException, BrokenBarrierException
// await() 메서드와 대부분 동일하며 timeout 설정과 관련된 부분만 차이가 남
// 이 장벽에서 모든 파티가 await 를 호출할 때까지 기다리며 현재 스레드가 마지막으로 도착한 것이 아닌 경우 다음 중 하나가 발생할 때까지 대기 상태에 있다
6) 지정된 타임아웃이 경과함
// 지정된 대기 시간이 경과하면 TimeoutException이 발생하며 시간이 0 이하이면 메서드는 전혀 대기하지 않는다
public boolean await(long timeout, TimeUnit unit) throws InterruptedException
// 이 장벽을 작동시키기 위해 필요한 파티의 수(스레드 수)를 반환한다
int getParties()
// 현재 장벽이 깨진 상태인지 확인한다
// 만약 생성 이후나 마지막 재 설정 이후로 인터럽트나 타임아웃으로 하나 이상의 스레드가 이 장벽에서 벗어났거나 예외로 인해 장벽 액션이 실패했다면 true 를 반환하며 그렇지 않으면 false를 반환한다
boolean isBroken()
// 이 장벽을 초기 상태로 재 설정한다
// 현재 장벽에서 대기 중인 스레드가 있는 경우 이들은 BrokenBarrierException을 반환한다
void reset()
CyclicBarrier vs CountDownLatch #