Tomcat과 같은 thread per request 전략을 사용하는 애플리케이션에 많은 요청이 밀려들었다. 그 때마다 thread를 생성하고 소멸시킨다면 자원이 많이 낭비되지 않을까?
이 문제를 해결하기 위한 방법 중 하나로 Thread Pool이 있다. 미리 Thread를 생성해두고, Task를 수행할 Thread를 할당하고 수거함으로써 자원 낭비를 줄일 수 있게 된다.
이처럼 생성/소멸에 자원이 많이 소모되는 환경에서 이를 미리 만들어 둔 그룹을
pool이라고 한다.
Thread Pool뿐 아니라 DB와의Connection을 만들어 둔Connection Pool도 있다.
그렇다면 Java에서 이런 Thread Pool을 어떻게 생성하고 관리할까?
Java 5를 기점으로 Executor, ExecutorService 라는 인터페이스가 등장했다.
public interface Executor {
void execute(Runnable runnable);
}
Executor는 Thread Pool에 Task를 실행시키는 추상화, Functional interface 형식ExecutorService extends Executor는 Task 실행에서 더 나아가 Thread Pool이 가져야 할 기능의 추상화이다.우리는 이 인터페이스의 구현체 중 하나인 ThreadPoolExecutor살펴보자.
일단 ThreadPoolExecutor의 계층 구조는 위와 같다.

객체 생성 방식은 크게 두 가지이다.
- new + 생성자
Executors의 팩토리 메서드 (single/fixed/cached)
우리는 핵심이 되는 "thread가 생성되고 소멸되는 과정" 을 알아보자.
어차피 Executors에 의한 3가지 ThreadPoolExecutor는 corePoolSize, MaxPoolSize, keepAlive 인자 차이일 뿐이다.
corePoolSize : 쓰레드 풀이 유지할 쓰레드 수maxPoolSize : 쓰레드 풀이 가질 수 있는 최대 쓰레드 수keepAlive : 쓰레드가 task 종료 후 살아있을 시간 (corePoolSize 이상 일 때)queueSize : waitingQueue 사이즈active thread가 corePoolSize 미만이라면, 새 thread를 생성
corePoolSize <= active <= MaxPoolSize 라면 Task를 Queue에 추가
이때 Queue가 가득 찼다면 새 thread 생성
단, active < MaxPoolSize일 경우에만이다.
Queue가 가득 차고, thread 수가 maxPoolSize이라면 해당 Task는 Reject가 된다. ... RejectedExecutionException
여기서 keepAlive 인자가 사용된다. Thread Pool은 불필요한 자원 소모를 방지하기 위해, corePoolSize를 넘는 Thread는 Task 종료 후 keepAlive가 지나면 이 thread를 소멸시킨다.
주요한 특징은
corePoolSize유지 &새 Thread 생성 보다는 Queue에 추가