[Java] ThreadPoolExecutor

민지·2024년 3월 12일
0

Java

목록 보기
6/9
post-thumbnail

오늘의 질문

ThreadPoolExecutor는 어떻게 동작하나요?

Thread Pool

쓰레드를 미리 생성하고, 작업 요청이 발생할 때 마다 미리 생성된 쓰레드로 해당 작업을 처리하는 방식.

사용이유

서버가 모든 요청에 대해 스레드를 매번 생성하게 하면 메모리 초과로 서버가 다운될 수 있기 때문.
일정 수의 스레드를 미리 생성해놓고 할당하는 방식으로 동시 처리를 진행한다.

ThreadPoolExecutor

여러 풀링된 스레드 중 하나를 사용하여 제출된 각 작업을 실행하는 객체.

java에서 스레드 실행은 ThreadPoolExecutor가 한다

ThreadPoolExecutor 객체를 생성하려고 하면 다음과 같은 생성자가 존재한다.

  • 주어진 초기 매개변수와 기본 스레드 팩토리 및 거부된 실행 핸들러를 사용하여 새로운 ThreadPoolExecutor를 생성합니다.
  • 주어진 초기 매개변수와 기본 스레드 팩토리를 사용하여 새로운 ThreadPoolExecutor를 생성합니다.
  • 주어진 초기 매개변수와 기본 거부 실행 핸들러를 사용하여 새로운 ThreadPoolExecutor를 생성합니다.
  • 주어진 초기 매개변수를 사용하여 새로운 ThreadPoolExecutor를 생성합니다.

여기서 공통으로 가지는 파라미터에 대해 알아보자.

공통 파라미터

  • corePoolSize
    • AllowCoreThreadTimeOut이 설정되지 않은 한 유휴 상태인 경우에도 풀에 보관할 스레드 수.
    • 기본으로 풀에 생성되는 스레드 수
  • maximumPoolSize
    • 풀에 허용되는 최대 스레드 수
  • keepAliveTime
    • 스레드 수가 코어보다 많아졌을 경우 maximumPoolSize까지 스레드가 생성되는데 이 시간만큼 유지하다가 다시 코어사이즈로 돌아오는 시간
  • unit
    • keepAliveTime의 시간 단위 (Ex.SECONDS)
  • workQueue
    • 작업이 실행되기 전에 작업을 보관하는 데 사용할 큐.
    • 이 큐는 실행 메소드에 의해 제출된 실행 가능한 작업만 보유.
    • corePoolSize보다 스레드가 많아졌을 경우, 남는 스레드가 없을 경우 해당 큐에 담는다.

동작과정 예시

corePoolSize = 1
maximumPoolSize = 5
keepAliveTime = 3
unit = SECONDS
workQueue = 7 (최대 7개의 쓰레드가 보관이 가능하다.)

해당 설정의 스레드 풀이 있다고 하자.

10개의 요청이 동시에 들어와 10개의 스레드가 필요하다면?

1. corePoolSize 만큼 스레드 실행.

  • 10 - 1 = 9개의 스레드 더 필요함

2. workQueue 사이즈만큼 큐에 스레드 보관

  • 7개의 요청 대기
  • 9 - 7 = 2개의 스레드 더 필요함.

3. maximumPoolSize가 5개이므로 현재 1개만 실행중이니 4개의 스레드 생성이 가능함.

  • 큐에도 보관되지 못한 나머지 2개를 실행시킨다.

예시 코드

import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;

import static java.util.concurrent.TimeUnit.SECONDS;

public class WebServer {
    public static void main(String args[]) throws Exception {
        //해당 큐는 7개까지 쓰레드 저장이 가능하다.
        LinkedBlockingQueue<Runnable> queue = new LinkedBlockingQueue<>(7);

        ThreadPoolExecutor executorService =
                new ThreadPoolExecutor(1,5,3, SECONDS, queue);

        for (int i = 0; i < 10; i++) {
            //10개의 Task를 실행시킨다.
            executorService.execute(new Task());
        }

        executorService.awaitTermination(5, SECONDS);
        executorService.shutdown();
    }

    private static class Task implements Runnable {
        @Override
        public void run() {
            try {
                //쓰레드 번호를 출력해 준다.
                System.out.println(Thread.currentThread().getName());
                SECONDS.sleep(1);
            } catch (InterruptedException e) {
            }
        }
    }
}

실행결과

위와 같은 결과가 나오게 된다.
3개씩 스레드가 생성된 것을 확인할 수 있다.

오늘의 대답

ThreadPoolExecurator는 지정해주는 파라미터를 통해 몇 개의 스레드를 동시에 실행할지 결정합니다.
기본적으로 corePoolSize만큼의 스레드를 실행합니다.
아직 필요한 스레드가 있을 시에 지정해준 workQueue의 사이즈만큼의 스레드를 큐에 넣습니다.
여전히 스레드가 존재하면 스레드 개수를 늘려줍니다. 이때 maximumPoolSize만큼의 스레드가 생성이 되고, 만약 이 값보다 큰 값의 스레드가 필요할 경우 에러가 발생하게 됩니다.
maximumPoolSize만큼 증가한 스레드 수는 keepAliveTime만큼 생겼다가 다시 corePoolSize로 돌아가게 됩니다.

참고

https://vsh123.github.io/os/thread-pool/

profile
개발의, 개발에 의한, 개발을 위한 기록장

0개의 댓글

관련 채용 정보