2026년 상식닷컴 선정 식당 & 카페 리스트
최근에 오픈한 호텔을 찾는다면 살펴보세요

스레드풀의 작업이 완료될 때까지 기다리는 방법은 무엇인가요?

_____
Q: 스레드풀(ThreadPool)에서 제출한 작업들이 모두 완료될 때까지 어떻게 기다릴 수 있나요?

A: 스레드풀에서 작업이 완료될 때까지 기다리는 일반적인 방법은 다음과 같습니다.

1. ExecutorService의 `shutdown()`과 `awaitTermination()` 사용하기
- 작업 제출이 완료된 후 `shutdown()` 메서드를 호출하여 더 이상 작업을 받지 않도록 스레드풀을 종료 시도합니다.
- 이후 `awaitTermination(long timeout, TimeUnit unit)` 메서드를 호출하면 지정한 시간 동안 모든 작업이 완료되기를 대기합니다.
- 예시:
```java
ExecutorService executor = Executors.newFixedThreadPool(4);
// 작업 제출
executor.shutdown();
try {
if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
executor.shutdownNow(); // 시간이 다되었으면 강제 종료
}
} catch (InterruptedException e) {
executor.shutdownNow();
Thread.currentThread().interrupt();
}
```
- 이 방법은 스레드풀이 종료되고, 제출된 모든 작업이 끝날 때까지 기다립니다.

2. `Future.get()` 이용하기
- 작업을 제출할 때 `submit()` 메서드를 사용하여 `Future` 객체를 받으면, 각 `Future`의 `get()` 메서드를 호출하여 해당 작업의 완료까지 대기할 수 있습니다.
- 예시:
```java
List> futures = new ArrayList<>();
for (Runnable task : tasks) {
futures.add(executor.submit(task));
}
for (Future future : futures) {
try {
future.get(); // 작업 완료 시까지 대기
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
```
- 모든 `Future.get()` 호출이 종료되면, 모든 작업이 완료된 상태입니다.

3. CountDownLatch 같은 동기화 도구 사용하기
- 여러 작업의 완료 시점을 알아야 한다면, `CountDownLatch`를 사용하여 각 작업이 끝날 때마다 `countDown()`을 호출하도록 한 후, 메인 스레드에서 `await()`로 대기합니다.
- 예시:
```java
int taskCount = tasks.size();
CountDownLatch latch = new CountDownLatch(taskCount);
for (Runnable task : tasks) {
executor.submit(() -> {
try {
task.run();
} finally {
latch.countDown();
}
});
}
latch.await(); // 모든 작업 완료 시까지 대기
```

요약:
- 모든 작업 제출이 끝난 후 `shutdown()` + `awaitTermination()`으로 스레드풀 전체 종료를 기다린다.
- 또는 각 작업의 `Future.get()`을 호출하여 작업별 완료를 명시적으로 기다린다.
- 더 정교한 동기화가 필요하면 `CountDownLatch` 등 별도의 동기화 도구를 사용한다.

이들 방법을 통해 스레드풀 내 모든 작업이 완료될 때까지 효과적으로 기다릴 수 있습니다.
스레드풀(ThreadPool)은 멀티스레딩 환경에서 작업을 효율적으로 관리하기 위해 사용되는 중요한 개념입니다.

스레드풀은 미리 생성된 스레드의 집합으로, 작업이 들어오면 대기 중인 스레드가 이를 처리합니다.

이로 인해 스레드를 매번 생성하고 소멸시키는 오버헤드를 줄일 수 있습니다.

그러나 스레드풀에서 수행되는 작업이 완료될 때까지 기다려야 하는 경우가 종종 있습니다.

이때 사용할 수 있는 여러 가지 방법이 있습니다.

1. `Future` 객체 사용하기 Java의 `ExecutorService`를 사용하여 스레드풀에서 작업을 제출할 때, `submit()` 메서드는 `Future` 객체를 반환합니다.

이 객체는 작업의 결과를 나타내며, `get()` 메서드를 호출하여 작업이 완료될 때까지 기다릴 수 있습니다.

```java ExecutorService executor = Executors.newFixedThreadPool(

10); Future future = executor.submit(() -> { // 작업 수행 return result; }); try { ResultType result = future.get(); // 작업 완료까지 대기 } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } finally { executor.shutdown(); } ```

2. `CountDownLatch` 사용하기 `CountDownLatch`는 특정 작업이 완료될 때까지 대기할 수 있는 동기화 도구입니다.

여러 개의 작업이 있을 때, 각 작업이 완료될 때마다 카운트를 감소시키고, 카운트가 0이 될 때까지 대기할 수 있습니다.

```java ExecutorService executor = Executors.newFixedThreadPool(

10); CountDownLatch latch = new CountDownLatch(numberOfTasks); for (int i = 0; i < numberOfTasks; i++) { executor.submit(() -> { try { // 작업 수행 } finally { latch.countDown(); // 작업 완료 시 카운트 감소 } }); } latch.await(); // 모든 작업이 완료될 때까지 대기 executor.shutdown(); ```

3. `CompletionService` 사용하기 `CompletionService`는 작업이 완료되는 대로 결과를 가져올 수 있는 구조입니다.

`ExecutorCompletionService`를 사용하면, 작업이 완료될 때마다 결과를 가져올 수 있습니다.

```java ExecutorService executor = Executors.newFixedThreadPool(

10); CompletionService completionService = new ExecutorCompletionService<>(executor); for (int i = 0; i < numberOfTasks; i++) { completionService.submit(() -> { // 작업 수행 return result; }); } for (int i = 0; i < numberOfTasks; i++) { try { Future future = completionService.take(); // 완료된 작업 대기 ResultType result = future.get(); // 결과 가져오기 } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } } executor.shutdown(); ```

4. `ForkJoinPool` 사용하기 Java 7부터 도입된 `ForkJoinPool`은 작업을 분할하고 병렬로 처리하는 데 최적화된 스레드풀입니다.

`ForkJoinTask`를 사용하여 작업을 제출하고, `invokeAll()` 메서드를 통해 모든 작업이 완료될 때까지 대기할 수 있습니다.

```java ForkJoinPool forkJoinPool = new ForkJoinPool(); List> tasks = new ArrayList<>(); for (int i = 0; i < numberOfTasks; i++) { tasks.add(forkJoinPool.submit(() -> { // 작업 수행 return result; })); } ForkJoinTask.invokeAll(tasks); // 모든 작업 완료 대기 forkJoinPool.shutdown(); ``` 결론 스레드풀의 작업이 완료될 때까지 기다리는 방법은 여러 가지가 있으며, 각 방법은 특정 상황에 따라 장단점이 있습니다.

`Future` 객체를 사용하면 간단하게 작업 결과를 얻을 수 있고, `CountDownLatch`는 여러 작업을 동시에 관리할 때 유용합니다.

`CompletionService`는 작업이 완료되는 대로 결과를 처리할 수 있는 장점이 있으며, `ForkJoinPool`은 대규모 병렬 처리에 적합합니다.

상황에 맞는 방법을 선택하여 효율적으로 스레드풀의 작업을 관리하세요.

작성자: 박시현 [비회원] | 작성일자: 1년 전 2024-11-21 22:51:34
조회수: 160 | 댓글: 0 | 좋아요: 0 | 싫어요: 0
내용이 부정확하다면 싫어요를 클릭해주세요.