CompletionService — 비동기 태스크 생산과 소비 분리
CompletionService — 비동기 태스크 생산과 소비 분리
CompletionService<V>는 새 비동기 태스크의 생산과 완료된 태스크 결과의 소비를 분리해주는 서비스예요. 여러 작업을 제출해 놓고, 완료되는 순서대로 결과를 꺼내 처리하고 싶을 때 유용해요.
본문
개념 이해하기
생산자(producer)가 태스크를 submit으로 실행을 요청하고, 소비자(consumer)가 완료된 태스크를 take로 꺼내 완료된 순서대로 결과를 처리해요.
예를 들어 비동기 I/O를 관리할 때 쓸 수 있어요. 읽기를 수행하는 태스크를 시스템의 한 부분에서 제출하고, 읽기가 끝나면 다른 부분에서 — 요청된 순서와 다를 수 있게 — 처리하는 식이에요.
일반적으로 CompletionService는 실제 실행을 위해 별도의 Executor에 의존하고, 서비스 자체는 내부 완료 큐만 관리해요. ExecutorCompletionService가 이런 접근의 구현체예요.
public interface CompletionService<V>
타입 매개변수 V는 이 서비스의 태스크가 생산·소비하는 값의 타입이에요.
메모리 일관성 효과: 한 스레드가 CompletionService에 태스크를 제출하기 전의 동작은 그 태스크가 수행하는 동작보다 happen-before이고, 이는 다시 대응하는 take()의 성공적 반환에 뒤따르는 동작보다 happen-before예요.
태스크 제출
Future<V> submit(Callable<V> task)
값을 반환하는 태스크를 실행을 위해 제출하고, 태스크의 대기 중 결과를 나타내는 Future를 반환해요. 완료되면 이 태스크는 take나 poll로 가져올 수 있어요.
task— 제출할 태스크RejectedExecutionException— 태스크를 실행으로 예약할 수 없을 때NullPointerException—task가null일 때
Future<V> submit(Runnable task, V result)
Runnable 태스크를 실행을 위해 제출하고, 그 태스크를 나타내는 Future를 반환해요. 완료 시 get()은 주어진 result를 반환해요.
task— 제출할 태스크result— 성공적으로 완료되면 반환할 결과RejectedExecutionException/NullPointerException
완료된 태스크 소비
Future<V> take() throws InterruptedException
다음으로 완료된 태스크를 나타내는 Future를 꺼내 제거해요. 아직 없으면 기다려요.
- 반환: 다음으로 완료된 태스크를 나타내는
Future InterruptedException— 대기 중 인터럽트
Future<V> poll()
다음으로 완료된 태스크를 나타내는 Future를 꺼내 제거하거나, 아무것도 없으면 null을 반환해요.
Future<V> poll(long timeout, TimeUnit unit) throws InterruptedException
다음으로 완료된 태스크를 나타내는 Future를 대기하며 꺼내요. 최대 timeout까지 기다리고, 시간이 지나면 null.
timeout— 포기하기 전 기다릴 시간(unit단위)unit—timeout을 해석하는TimeUnitInterruptedException— 대기 중 인터럽트