ExecutorService — 종료 관리와 Future 제공 Executor
ExecutorService — 종료 관리와 Future 제공 Executor
ExecutorService는 종료(termination)를 관리하는 메서드와 하나 이상의 비동기 태스크 진행을 추적하는 Future 를 생성하는 메서드를 제공하는 Executor예요. 자바에서 스레드 풀을 다룰 때 가장 흔히 쓰는 인터페이스예요.
본문
개념 이해하기
ExecutorService는 종료 관리 메서드와 비동기 태스크의 진행을 추적하는 Future를 생성하는 메서드를 제공하는 Executor예요. 종료되면 새 태스크를 거부해요.
public interface ExecutorService
extends Executor, AutoCloseable
shutdown(): 이미 제출된 태스크는 실행하게 하되 새 태스크는 받지 않는 질서 있는 정리를 시작해요.shutdownNow(): 대기 태스크는 시작하지 못하게 하고, 실행 중인 태스크를 중지하려 시도해요.- 완료 시: 실행 중 태스크도, 실행 대기 태스크도 없고 새 태스크 제출도 불가능해요. 사용하지 않는
ExecutorService는 자원 회수를 위해 종료해야 해요. submit은Executor.execute(Runnable)를 확장해 실행 취소/완료 대기에 쓰는Future를 만들어 반환해요.invokeAny/invokeAll은 태스크 컬렉션을 실행하고 하나 또는 모두가 완료될 때까지 기다리는 일괄 실행을 제공해요.Executors클래스가 이 패키지의 executor 서비스 팩토리 메서드를 제공해요.
활용 예 — 네트워크 서비스
class NetworkService implements Runnable {
private final ServerSocket serverSocket;
private final ExecutorService pool;
public NetworkService(int port, int poolSize) throws IOException {
serverSocket = new ServerSocket(port);
pool = Executors.newFixedThreadPool(poolSize);
}
public void run() {
try {
for (;;) { pool.execute(new Handler(serverSocket.accept())); }
} catch (IOException ex) { pool.shutdown(); }
}
}
try-with-resources로도 열고 닫을 수 있어요 (JDK 19+ close):
try (ExecutorService e = Executors.newWorkStealingPool()) {
// submit or execute many tasks with e ...
}
활용 예 — 두 단계 종료
void shutdownAndAwaitTermination(ExecutorService pool) {
pool.shutdown(); // Disable new tasks from being submitted
try {
if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {
pool.shutdownNow(); // Cancel currently executing tasks
if (!pool.awaitTermination(60, TimeUnit.SECONDS))
System.err.println("Pool did not terminate");
}
} catch (InterruptedException ex) {
pool.shutdownNow(); // (Re-)Cancel if current thread also interrupted
Thread.currentThread().interrupt(); // Preserve interrupt status
}
}
메모리 일관성 효과: 한 스레드에서 태스크를 제출하기 전의 동작은 그 태스크가 수행하는 동작보다 happen-before이고, 이는 다시 Future.get()으로 결과를 가져오기 전에 happen-before예요.
종료 메서드
void shutdown() — 질서 있는 정리를 시작해요. 이미 종료됐으면 추가 효과가 없어요. 제출된 태스크가 완료되길 기다리지 않아요(awaitTermination 사용).
SecurityException— 보안 관리자 존재 시
List<Runnable> shutdownNow() — 실행 중인 태스크를 모두 중지하려 시도하고 대기 태스크 처리를 중단하며, 실행 대기 중이던 태스크 목록을 반환해요. best-effort만 보장해요(보통 Thread.interrupt()로 취소하므로 인터럽트에 응답하지 않는 태스크는 끝나지 않을 수 있어요).
SecurityException
boolean isShutdown() — 종료됐으면 true.
boolean isTerminated() — 종료 후 모든 태스크가 완료됐으면 true. shutdown/shutdownNow가 먼저 호출되지 않으면 true가 되지 않아요.
boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException — 종료 요청 후 모든 태스크가 완료되거나, 타임아웃이 발생하거나, 인터럽트될 때까지 블로킹해요. 종료됐으면 true, 타임아웃이면 false.
InterruptedException
default void close() — 질서 있는 정리를 시작하고 모든 태스크 완료·executor 종료까지 대기해요. 대기 중 인터럽트되면 shutdownNow()처럼 실행 태스크를 멈추고, 실행 중 태스크가 끝날 때까지 계속 기다려요. (JDK 19+)
submit 메서드
<T> Future<T> submit(Callable<T> task) — 값을 반환하는 태스크를 제출하고 대기 중 결과를 나타내는 Future를 반환해요. result = exec.submit(aCallable).get(); 형태로 블로킹 대기할 수 있어요.
RejectedExecutionException,NullPointerException
<T> Future<T> submit(Runnable task, T result) — Runnable 태스크를 제출하고 그 태스크를 나타내는 Future를 반환해요. 완료 시 get()은 result를 반환.
RejectedExecutionException,NullPointerException
Future<?> submit(Runnable task) — Runnable 태스크를 제출하고 그 태스크를 나타내는 Future를 반환해요. 완료 시 get()은 null을 반환.
RejectedExecutionException,NullPointerException
일괄 실행
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException — 주어진 태스크를 실행하고 모두 완료될 때 상태·결과를 담은 Future 목록을 반환해요. 반환 목록의 각 요소는 Future.isDone()이 true예요. 완료된 태스크는 정상 종료이거나 예외를 던져 끝났을 수 있어요. 연산 중 컬렉션이 수정되면 결과는 정의되지 않아요.
InterruptedException(대기 중 인터럽트 — 미완료 태스크는 취소),NullPointerException,RejectedExecutionException
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException — 모두 완료되거나 타임아웃이 지날 때 중 먼저 일어나는 때의 상태·결과 Future 목록을 반환해요. 반환 시 완료되지 않은 태스크는 취소돼요.
InterruptedException,NullPointerException,RejectedExecutionException
<T> T invokeAny(Collection<? extends Callable<T>> tasks) throws InterruptedException, ExecutionException — 성공적으로 완료된(예외를 던지지 않은) 하나의 태스크 결과를 반환해요. 정상·예외 반환 시 완료되지 않은 태스크는 취소돼요.
InterruptedException,NullPointerException,IllegalArgumentException(tasks가 비었을 때),ExecutionException(성공 완료 태스크가 없을 때),RejectedExecutionException
<T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException — 타임아웃 전에 성공 완료된 하나의 태스크 결과를 반환해요.
TimeoutException(타임아웃 전 성공 완료 태스크 없음) 등