ForkJoinPool 완벽 이해하기
이전 글에서:
- ExecutorService
- ThreadPoolExecutor
- CompletableFuture
를 배웠다.
그런데 CompletableFuture.supplyAsync()를 설명하면서 이런 말을 했다.
CompletableFuture.supplyAsync(...)
기본적으로는
ForkJoinPool.commonPool()
을 사용한다.
그럼 질문이 생긴다.
ForkJoinPool은 일반 ThreadPool과 뭐가 다른가?
왜 CompletableFuture가 ForkJoinPool을 사용하는가?
parallelStream()은 왜 빨라지는가?
이번 글에서 전부 연결된다.
1. ForkJoinPool이란?
ForkJoinPool
한 줄 정의.
작업을 잘게 쪼개고(Fork),
결과를 합치는(Join)
병렬 처리용 ThreadPool
2. 일반 ThreadPool 방식
예:
100만 건 데이터 처리
ThreadPool
Thread1
↓
100만 건 처리
또는
Thread1
↓
50만 건
Thread2
↓
50만 건
직접 나눠야 함.
3. ForkJoinPool 방식
자동 분할.
100만 건
↓
50만
50만
↓
25만
25만
25만
25만
CPU 코어 수에 맞춰 계속 쪼갠다.
4. 이름의 의미
Fork
작업 분할
Join
결과 병합
5. 그림
100
↓
Fork
50 50
↓ ↓
25 25 25 25
↓ ↓
Join
↓
100
6. 왜 만들었을까?
멀티코어 CPU 활용.
예전
CPU 1코어
현재
CPU 8코어
CPU 16코어
CPU 32코어
병렬 처리 필요.
7. 대표 예제
1~100000000 합계.
일반 방식
long sum = 0;
for(...) {
sum += i;
}
코어 1개 사용.
8. ForkJoinPool
1~100000000
↓
1~50000000
50000001~100000000
병렬 계산.
9. 핵심 클래스
두 개만 기억.
RecursiveTask
결과 있음.
class SumTask
extends RecursiveTask<Long>
RecursiveAction
결과 없음.
class PrintTask
extends RecursiveAction
10. RecursiveTask 예제
class SumTask
extends RecursiveTask<Long> {
private long start;
private long end;
}
11. compute()
핵심 메서드.
@Override
protected Long compute() {
}
실제 작업 수행.
12. 종료 조건
예:
if(end - start < 1000)
직접 계산.
long sum = 0;
for(...) {
}
13. 크면?
반으로 분할.
long middle =
(start + end) / 2;
14. Fork
SumTask left =
new SumTask(
start,
middle
);
left.fork();
의미
다른 Thread에게 맡김
15. 현재 Thread
오른쪽 작업 수행.
right.compute();
16. Join
left.join();
결과 기다림.
17. 최종
leftResult
+
rightResult
반환.
18. 흐름
10000
↓
5000
5000
↓
2500
2500
2500
2500
↓
계산
↓
합치기
19. 가장 중요한 특징
Work Stealing.
면접 단골.
20. 일반 ThreadPool 문제
Thread1 바쁨
Thread2 바쁨
Thread3 놀고 있음
CPU 낭비.
21. ForkJoinPool 해결
각 Thread가
자기 Queue
보유.
22. 구조
Thread1 Queue
Thread2 Queue
Thread3 Queue
23. Thread3가 할 일 없으면?
다른 Queue 확인.
Thread1 Queue
에서
작업 훔쳐옴.
24. 이것이
Work Stealing
25. 그림
Thread1
Task
Task
Task
↓
Thread3
하나 훔침
26. 장점
CPU 활용 극대화.
27. 왜 빠른가?
일반 ThreadPool.
Queue 1개
모든 Thread 경쟁.
28. ForkJoinPool
Queue 여러 개
경쟁 감소.
29. parallelStream()
매우 중요.
예:
list.parallelStream()
내부적으로
ForkJoinPool
사용.
30. 예제
list.parallelStream()
.map(...)
.filter(...)
.toList();
자동 병렬 처리.
31. CompletableFuture
기본 실행기.
CompletableFuture
.supplyAsync(...)
기본적으로
ForkJoinPool.commonPool()
사용.
32. commonPool()
전역 Pool.
JVM 전체 공유.
ForkJoinPool.commonPool()
33. 문제
실무 중요.
모든 작업.
CompletableFuture
parallelStream
기타 라이브러리
같은 Pool 사용 가능.
34. 결과
Pool 고갈
위험.
35. 실무 방식
Executor 직접 지정.
CompletableFuture
.supplyAsync(
task,
executor
);
36. ForkJoinPool이 적합한 작업
대표.
대규모 계산
재귀 분할 가능
CPU Bound
37. 적합하지 않은 작업
대표.
DB 조회
API 호출
파일 읽기
38. 왜?
I/O 대기 발생.
ForkJoinPool Thread가
대기 상태
됨.
CPU 활용 저하.
39. CPU Bound vs I/O Bound
매우 중요.
| 계산 작업 | 좋음 |
| DB 조회 | 별로 |
| API 호출 | 별로 |
| 파일 읽기 | 별로 |
40. Spring 실무
대부분.
@Async
↓
ThreadPoolTaskExecutor
사용.
ForkJoinPool 직접 사용 적음.
41. 면접 단골 질문
Q. ForkJoinPool이란?
Fork
=
작업 분할
Join
=
결과 병합
Q. RecursiveTask와 RecursiveAction 차이?
RecursiveTask
=
결과 있음
RecursiveAction
=
결과 없음
Q. Work Stealing이란?
유휴 Thread가
다른 Thread Queue의 작업을 가져오는 것
Q. parallelStream 내부 구현은?
ForkJoinPool
Q. CompletableFuture 기본 Pool은?
ForkJoinPool.commonPool()
Q. ForkJoinPool이 적합한 작업은?
CPU Bound
42. 지금까지 흐름 연결
Thread
↓
Runnable
↓
ExecutorService
↓
ThreadPoolExecutor
↓
Future
↓
CompletableFuture
↓
ForkJoinPool
43. 핵심 흐름 요약
큰 작업
↓
Fork
(분할)
↓
여러 Thread 처리
↓
Work Stealing
↓
Join
(결과 병합)
↓
완료
44. 가장 중요한 핵심 한 줄
ForkJoinPool은 큰 작업을 작은 작업으로 분할(Fork)하여 여러 스레드에서 병렬 처리하고, Work Stealing을 통해 CPU 활용도를 극대화한 Java의 고성능 병렬 처리 프레임워크이다.
45. 다음 글 예고
다음 글은:
ReentrantLock
이다.
여기서부터는:
synchronized
VS
ReentrantLock
비교,
그리고
공정성(Fairness)
tryLock()
lockInterruptibly()
Condition
같은 실무 기능들을 배우게 된다.
많은 개발자가 synchronized만 알지만, 실무에서는 특정 상황에서 ReentrantLock이 더 강력한 선택지가 된다.
'language > java' 카테고리의 다른 글
| DeadLock(교착상태) 원인과 해결 완벽 이해하기 (0) | 2026.06.01 |
|---|---|
| ReentrantLock 완벽 이해하기 (0) | 2026.06.01 |
| CompletableFuture 완벽 이해하기 (0) | 2026.06.01 |
| ThreadPool 구조 완벽 이해하기 (0) | 2026.06.01 |
| ExecutorService 완벽 이해하기 (0) | 2026.06.01 |
댓글