본문 바로가기
language/java

ForkJoinPool 완벽 이해하기

by 죄니안죄니 2026. 6. 1.
반응형

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

매우 중요.

종류ForkJoinPool
계산 작업 좋음
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이 더 강력한 선택지가 된다.

반응형

댓글