비동기 처리를 담당하는 쓰레드풀을 설정하기 위해 Spring이 제공하는 ThreadPoolExecutor를 사용했다. 튜닝할 수 있는 값들이 corePoolSize, maxPoolSize, queueCapacity 가 있었는데 어떻게 튜닝을 하는게 좋을지 학습해봤다.
Executor 프레임워크가 작업의 정의 부분과 실행 부분을 분리시켜준다. 특정 형태의 실행 정책에서는 실행할 수 없다.
쓰레드풀은 동일하고 서로 독립적인 다수의 작업을 실행할 때 가장 효과적이다. 일반적으로 네트워크 기반의 서버 애플리케이션은 작업이 서로 동일하면서 독립적이야 한다는 조건을 대부분 만족한다.
스레드 부족 데드락
만약 쓰레드풀에서 다른 작업에 의존성을 갖고 있는 작업을 실행시키면 데드락에 걸릴 가능성이 높다.
오래 실행되는 작업
특정 작업이 긴 시간동안 종료되지 않고 실행되면 응답속도에 문제가 생긴다. 쓰레드 풀의 응답 속도가 크게 느려진다.
스레드 풀의 가장 이상적인 크기는 스레드 풀에서 실행할 작업의 종류와 스레드 풀을 활용할 애플리케이션의 특성에 따라 결정된다. 쓰레드 풀의 크기를 하드코딩해 고정하기보다는 동적으로 지정되도록 해야 한다.
쓰레드 풀의 크기가 너무 크다면 스레드는 CPU나 메모리를 확보하기 위해 경쟁하게 되고, CPU에는 부하가 걸리고 메모리는 모자라 자원 부족에 시달릴 것이다.
쓰레드 풀의 크기가 너무 작으면 작업략이 계속 쌓이게 되는데 CPU와 메모리는 남아돌면서 작업 처리 속도가 떨어질 수 있다.
쓰레드풀의 크기를 적절하게 산정하려면 현재 컴퓨터 환경이 어느정도인지 확인해야한다. CPU를 많이 사용하는 작업의 경우 N개의 CPU를 탑재하고 있는 하드웨어에서 스레드풀을 사용할 때는 스레드의 개수를 N+1개로 맞추면 최적의 성능을 발휘한다고 알려져 있다.
스레드의 생성과 제거는 corePoolSize, maximumPoolSize, keepAliveTime으로 설정할 수 있다. 코어 크기는 스레드 풀을 사용할 때 원하는 쓰레드의 개수라고 볼 수 있다. 실행할 작업이 없더라도 스레드의 개수를 최대한 코어 크기에 맞추도록 되어 있다.
초기에 설정하려면 prestartAllCoreThreads
메서드를 호출해야 한다. 그렇지 않으면 작업이 실행되면서 코어 크기까지의 쓰레드가 차례로 생성된다.
queue에 작업이 가득차면 쓰레드를 새로 생성하여 풀의 최대크기 만큼 생성한다. 스레드 유지 시간 이상 아무런 작업 없이 대기하고 있던 스레드는 제거 대상 목록에 올라간다.
우리는 쓰레드풀의 corePoolSize를 1로 maximumPoolSize, queueSize를 Integer_Max_Value로 설정했다. Thread를 하나만 쓰기 때문에 멀티 쓰레드에서 발생할 위험을 안가져갈 수 있는 장점은 있다. 하지만 작업이 몰리게된다면 응답이 지연될 수 있다.
자바 병렬 프로그래밍 - 브라이언 게츠