본문 바로가기
language/java

ThreadPool 구조 완벽 이해하기

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

ThreadPool 구조 완벽 이해하기

이전 글에서:

 
ExecutorService executor =
    Executors.newFixedThreadPool(10);
 

를 배웠다.

그런데 실무 면접에서는 여기서 끝나지 않는다.

오히려 진짜 많이 나오는 질문은:

ThreadPool은 내부적으로 어떻게 동작하나요?

Core Pool Size와 Max Pool Size 차이는?

Queue가 꽉 차면 어떻게 되나요?

RejectedExecutionHandler는 뭔가요?

이다.


1. ThreadPool이란?

한 줄 정의.

Thread를 미리 생성해두고 재사용하는 구조
 

2. 왜 필요할까?

Thread 생성은 생각보다 비싸다.

Stack 생성
TCB 생성
OS 등록
Context Switch 준비
 

비용 발생.


그래서

Thread 생성
↓
사용
↓
버림
 

을 반복하지 않고

Thread 생성
↓
계속 재사용
 

한다.


3. 실제 구조

                Task 제출

                     ↓

              +-------------+
              |   Queue     |
              +-------------+

                 ↓     ↓

        +---------+  +---------+
        |Thread 1 |  |Thread 2 |
        +---------+  +---------+

        +---------+  +---------+
        |Thread 3 |  |Thread 4 |
        +---------+  +---------+
 

4. 실제 구현체

실무 핵심.

 
ThreadPoolExecutor
 

ExecutorService는 사실 인터페이스.

실제 동작은 대부분

 
ThreadPoolExecutor
 

가 수행.


5. 생성자

 
ThreadPoolExecutor(
    corePoolSize,
    maximumPoolSize,
    keepAliveTime,
    unit,
    workQueue,
    handler
)
 

6. 가장 중요한 4개

corePoolSize
maximumPoolSize
workQueue
RejectedExecutionHandler
 

7. 예제

 
ThreadPoolExecutor executor =
    new ThreadPoolExecutor(
        2,
        4,
        60,
        TimeUnit.SECONDS,
        new LinkedBlockingQueue<>(2)
    );
 

8. 의미

Core Thread = 2

Max Thread = 4

Queue = 2
 

9. 동작 순서

이 부분이 핵심.


10. Task 1 제출

현재 Thread 없음.


결과

Thread 1 생성
 

11. Task 2 제출

Thread 2 생성
 

현재

Thread 1
Thread 2
 

사용 중.


12. Task 3 제출

Core Thread 꽉 참.


그럼?

Queue 저장
 

13. Task 4 제출

Queue 저장
 

상태.

Thread 1 작업중
Thread 2 작업중

Queue
 ├─ Task3
 └─ Task4
 

14. Task 5 제출

Queue도 꽉 참.


이제

Max Thread까지 확장
 

시도.


15. 결과

Thread 3 생성
 

16. Task 6 제출

Thread 4 생성
 

상태.

Thread 1
Thread 2
Thread 3
Thread 4

Queue
 ├─ Task3
 └─ Task4
 

17. Task 7 제출

문제 발생.


현재

Core Thread 가득

Queue 가득

Max Thread 가득
 

더 이상 수용 불가.


18. 이때 등장

RejectedExecutionHandler
 

19. Reject Policy

작업 거부 정책.


대표적으로 4개.


20. AbortPolicy

기본값.


 
RejectedExecutionException
 

발생.


가장 많이 사용.


21. CallerRunsPolicy

호출한 Thread가 직접 실행
 

예:

 
executor.submit(...)
 

한 Thread가 직접 처리.


22. DiscardPolicy

그냥 버림
 

위험.


23. DiscardOldestPolicy

가장 오래된 Queue 제거
 

새 작업 추가.


24. keepAliveTime

매우 중요.


Core Thread 초과로 생성된 Thread.

예:

Thread 3
Thread 4
 

언제 제거될까?


25. keepAliveTime

 
60초
 

라면

60초 동안 놀고 있으면 제거
 

26. Core Thread는?

기본적으로 제거 안 됨.


Core Thread
= 상시 유지

Extra Thread
= 필요 시 생성
 

27. 전체 흐름

매우 중요.

면접 단골.

Task 제출
 ↓

Core Thread 남음?

 YES → Thread 생성

 NO
 ↓

Queue 공간 있음?

 YES → Queue 저장

 NO
 ↓

Max Thread 가능?

 YES → Thread 생성

 NO
 ↓

Reject Policy 실행
 

28. 그림으로 이해

Task

 ↓

[ Core Thread ]

 ↓ 꽉 참

[ Queue ]

 ↓ 꽉 참

[ Extra Thread ]

 ↓ 꽉 참

[ Reject ]
 

29. Executors.newFixedThreadPool 문제

예:

 
Executors.newFixedThreadPool(10)
 

많이 사용하지만

실무에서는 권장 안 함.


30. 이유

내부 Queue.

 
LinkedBlockingQueue
 

사실상

무제한
 

크기.


31. 위험

트래픽 폭증.


Task 계속 적재
 

메모리 증가
 

OutOfMemoryError
 

32. 실무 권장

직접 생성.

 
new ThreadPoolExecutor(
    10,
    20,
    60,
    TimeUnit.SECONDS,
    new LinkedBlockingQueue<>(1000),
    new ThreadPoolExecutor.AbortPolicy()
)
 

33. Spring에서

사실 실무는 대부분.

 
ThreadPoolTaskExecutor
 

사용.


내부는

 
ThreadPoolExecutor
 

래핑.


34. Spring 예시

 
@Bean
public Executor taskExecutor() {

    ThreadPoolTaskExecutor executor =
        new ThreadPoolTaskExecutor();

    executor.setCorePoolSize(10);

    executor.setMaxPoolSize(20);

    executor.setQueueCapacity(1000);

    return executor;
}
 

35. 실무 튜닝 포인트

CPU 작업.

Core ≈ CPU 코어 수
 

I/O 작업.

Core > CPU 코어 수
 

가능.


36. CPU Bound

예:

암호화
압축
영상 인코딩
 

37. I/O Bound

예:

DB 조회
API 호출
파일 읽기
 

실무 대부분은

I/O Bound
 

에 가깝다.


38. 면접 단골 질문

Q. ThreadPoolExecutor 동작 순서는?

Core

↓

Queue

↓

Max

↓

Reject
 

Q. Core Pool Size란?

항상 유지되는 Thread 수
 

Q. Max Pool Size란?

최대 생성 가능한 Thread 수
 

Q. Queue가 꽉 차면?

Max Thread 생성 시도
 

Q. Max까지 꽉 차면?

Reject Policy 실행
 

Q. 왜 Executors.newFixedThreadPool을 실무에서 조심해야 하나요?

무제한 Queue
↓
OOM 위험
 

39. ExecutorService와 ThreadPool 연결

지금까지 흐름.

new Thread()
 ↓

ExecutorService
 ↓

ThreadPoolExecutor
 ↓

Core Thread
Queue
Max Thread
Reject Policy
 

40. 핵심 흐름 요약

Task 제출
 ↓

Core Thread 사용

 ↓ 꽉 참

Queue 저장

 ↓ 꽉 참

Max Thread 생성

 ↓ 꽉 참

Reject Policy
 

41. 가장 중요한 핵심 한 줄

ThreadPoolExecutor는 Core Thread → Queue → Max Thread → Reject Policy 순서로 작업을 처리하며, 이를 통해 Thread 생성 비용을 줄이고 시스템 부하를 제어한다.
 

42. 다음 글 예고

다음 글은

CompletableFuture

이다.

여기서부터:

 
Future
 

의 한계,

 
thenApply()
thenCompose()
allOf()
exceptionally()
 

를 통한 비동기 프로그래밍,

그리고 Spring의

 
@Async
 

와의 연결까지 배우게 된다.

반응형

댓글