Executor<3>

sungs·2025년 7월 25일

자바

목록 보기
52/95

스레드 풀 관리

ExecutorService es = new ThreadPoolExecutor( corePoolSize, maximumPoolSize,keepAliveTime, TimeUnit unit,BlockingQueue workQueue)

  • corePoolSize: 스레드풀에서 기본으로 관리되는 기본 스레드 수다.
  • maximumPoolSize: 스레드풀에서 관리되는 최대 스레드 수다.
  • keepAliveTime, TimeUnit unit: 초과 스레드가 대기 공간에서 작업을 안 하고 살아남을 수 있는 시간이다.
  • BlockingQueue workQueue: 작업을 저장할 블록킹 큐다.

원리

  1. 일단 작업이 들어오면 corePoolSize를 확인하고 없으면 스레드를 생성해서 스레드가 작업을 처리하게 한다.
  2. 만약 corePoolsize가 꽉 찼는데 작업이 들어오면 작업을 저장한다.
  3. 큐에도 꽉 찼는데 더 들어오면 그땐 긴박한 상황이므로 초과 스레드를 만들어 작업을 처리하게 한다.
  4. 초과 스레드까지 다 찼는데도 들어오면 그땐 예외가 발생한다.

스레드 미리 생성하기

작업이 들어온 순간 스레드를 생성하는 대신 스레드를 미리 생성하고 싶으면 ThreadPoolExecutor.prestartAllCoreThreads()를 사용하면 기본 스레드를 미리 생성할 수 있다. 참고로 ExecutorService는 이 메서드를 제공하지 않는다.

스레드 풀 관리 전략

아무튼 new ThreadPoolExecutor( corePoolSize, maximumPoolSize,keepAliveTime, TimeUnit unit,BlockingQueue workQueue) 이를 잘 활용하여 다양한 Executor 전략을 사용할 수 있다.

단일 풀 전략

newSingleThreadPool()를 사용하는 전략이다. 스레드풀에 1개의 스레드만 있으며, 주로 테스트용으로 쓰인다.

고정 풀 전략

newFixedThreadPool(nThreads)를 사용하는 전략이다. 생성할 스레드 수를 미리 정해놓기 떄문에 사용할 cpu 리소스나 자원을 알 수 있어 예측 가능한 전략이다. 그 덕분에 안정적으로 사용할 수 있다는 장점이 있지만, 이는 단점도 된다. 이벤트를 열어 갑자기 너무 많은 사용자가 몰려오면 고정된 스레드 수 때문에 작업 처리 속도가 느려질 수 있다.

캐시 풀 전략

newCachedThreadPool()를 사용하는 전략이다. 초과 스레드를 무제한으로 생성하는 것과 더불어 저장 공간이 0인 SynchronousQueue을 사용하여 작업 수가 갑자기 급증하더라도 다 처리할 수 있다. 다만 이 또한 단점이 될 수 있는데 스레드를 무제한으로 생성하는 만큼 작업 수가 너무 많이 들어오면 cpu와 메모리를 완전히 사용할 수도 있다. 그렇게 되면 서버가 죽어버릴 가능성이 생긴다.

SynchronousQueue

큐에 저장 공간이 없다. 따라서 생산자가 소비자하고 직접 만나 작업을 건네는 직거래 방식이다. 좀 더 구체적으로 말하자면 생산자가 소비자를 기다리고 소비자가 오면 작업을 건네고 그 결과를 반환받는 형식이다.

사용자 정의 전략

사용자에 따라 다르게 사용할 수 있다. new ThreadPoolExecutor( corePoolSize, maximumPoolSize,keepAliveTime, TimeUnit unit,BlockingQueue workQueue) 이를 적절히 활용하는 방식이다. 예를 들어 new ThreadPoolExecutor(100, 200, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(1000)); 이렇게 정의할 경우 1100개까지는 기본 스레드로 처리하지만 넘어갈 경우 초과 스레드를 생성하여 처리한다. 만약 1200개도 넘어갈 경우 작업이 너무 만하다고 들어오느 작업을 거절해버린다. 이렇게 하면 딱 한계까지 cpu를 사용할 수 있고 작업도 좀 더 빠르게 처리할 수 있다.

예외 정책

작업이 너무 많이 들어와 거절당했을 때 어떻게 할지를 설정할 수 있다.
ExecutorService executor = new ThreadPoolExecutor(1, 1, 0, TimeUnit.SECONDS,new SynchronousQueue<>(), new ThreadPoolExecutor.AbortPolicy());
이런 형식으로 설정할 수 있다. 참고로 AbortPolicy는 기본 정책이므로 생략해도 된다.
사용자 정의인 경우에는 handler를 따로 만들어서 넣어주면 된다.

  • AbortPolicy: RejectedExecutionException라는 예외를 터뜨려 처리한다. 기본 정책이다.
  • DiscardPolicy: 새로운 작업을 조용히 버리는 것이다.
  • CallerRunsPolicy: 작업을 호출한 스레드한테 작업을 직업 처리하도록 하는 정책이다.
  • 사용자 정의(RejectedExecutionHandler): 개발자가 직업 정의하는 정책이다.
profile
앱 개발 공부 중

0개의 댓글