기본적으로 스레드 풀은 작업이 제출되면 corePoolSize의 새 스레드를 추가해서 작업을 할당하고 큐 작업을 바로 추가하지 않는다.
corePoolSize를 초과해서 스레드가 실행 중이면 새 스레드를 추가해서 작업을 할당하는 대신 큐에 작업을 추가한다.
만약 큐가 가득차게 되면 스레드가 maxPoolSize 이상까지 늘어나게 되고 maxPoolSize 이상 실행 중이면 더 이상 작업은 추가되지 않고 거부된다.
BlockingQueue 인터페이스를 구현한 구현체는 여러개가 있지만, ThreadPoolExecutor와 관련된 세 가지는 아래와 같다.
- SynchronousQueue
- LinkedBlockingQueue
- ArrayBlockingQueue
SynchronousQueue

BlockingQueue의 구현체인 SynchronousQueue는 Executors.newCachedThreadPool() 메서드 호출 시 사용되는 클래스이다.

SynchronousQueue는 내부적으로 크기가 0인 큐라서 큐에 작업을 넣을 수가 없다.
따라서 즉시 작업을 실행할 스레드가 필요한데, 만약 스레드 풀에 유휴 스레드가 없다면 새로운 스레드가 생성되어 작업을 처리한다.
SynchronousQueue는 스레드가 작업을 처리하는 속도보다 작업 요청 속도가 많으면 스레드가 무한정 증가할 수 있으므로 조심해야 한다.
LinkedBlockingQueue

LinkedBlockingQueue는 Executors.newFixedThreadPool() 에서 사용된다.

LinkedBlockingQueue는 무제한 크기의 큐이다.
따라서 corePoolSize의 스레드가 모두 사용중인 경우 새로운 작업이 제출되면 큐에 등록하고 대기시킨다.
무제한 크기의 큐이기 때문에 corePoolSize 개수를 초과하는 스레드를 생성할 필요가 없으므로 maximumPoolSize를 설정해도 아무런 효과가 없다.
LinkedBlockingQueue 방식은 일시적인 요청의 폭증을 완화하는데 유용할 수는 있지만, 평균적인 처리보다 작업이 더 빨리 도착하는 경우에는 큐가 무한정 증가할 수 있다.
ArrayBlockingQueue

ArrayBlockingQueue는 내부적으로 고정된 크기의 배열을 사용하여 큐의 최대 크기를 지정한다. 지정된 큐의 크기는 변경할 수 없다.
큐의 최대 크기를 너무 크게 잡아버리면 대기열이 크게 증가하여 낮은 처리량을 유발할 수도 있다.
따라서 thread corePoolSize, maximumPoolSize를 적당히 조절해가며 사용해야 한다.