CompletionService — 비동기 태스크 생산과 소비 분리

CompletionService — 비동기 태스크 생산과 소비 분리

CompletionService<V>새 비동기 태스크의 생산완료된 태스크 결과의 소비를 분리해주는 서비스예요. 여러 작업을 제출해 놓고, 완료되는 순서대로 결과를 꺼내 처리하고 싶을 때 유용해요.

출처: Java API Reference

본문

개념 이해하기

생산자(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를 반환해요. 완료되면 이 태스크는 takepoll로 가져올 수 있어요.

  • task — 제출할 태스크
  • RejectedExecutionException — 태스크를 실행으로 예약할 수 없을 때
  • NullPointerExceptiontasknull일 때

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 단위)
  • unittimeout을 해석하는 TimeUnit
  • InterruptedException — 대기 중 인터럽트

더 알아보기 (Learn more)