Java/Thread

[Java] 멀티 스레드(Multi Thread) (5) : 스레드풀의 생성과 종료

아, 그래요? 2021. 12. 10. 11:47
컴퓨터의 작업량이 점점 많아지면...

병렬로 처리할 작업의 양이 많아지면 자연스럽게 스레드의 양도 많아지게 된다. 스레드의 양이 많아지면 더 많은 스레드의 생성과 이에 따른 스케줄링으로 인해 CPU의 메모리 사용량은 점점 많아지게 되고, 컴퓨터의 성능 저하로 이어지게 된다. 이를 방지하기 위해 한 시스템 내에서 처리될 수 있는 스레드의 양을 제한할 필요성이 있고, 이때 사용할 수 있는것이 스레드풀(Thread Pool)이다.

 

스레드풀 (Thread Pool)

아래 그림을 보면 스레드풀(Thread Pool)에 자리가 남을 경우, 작업 큐(Task Queue)에서 스레드를 가져온다. 그리고 새로이 처리 되고자 하는 스레드는 작업 큐에 푸쉬되게 된다. 스레드 풀에 있는 스레드의 개수는 제한된 숫자를 넘을 수 없다.

출처 Wikipedia(https://en.wikipedia.org/wiki/Thread_pool)

 

자바는 java.util.concurrent 패키지에 있는 ExecutorService 인터페이스와 Executors 클래스를 통해 스레드풀을 생성할 수 있다. Executors 클래스의 정적 메소드를 통해 생성한 ExecutorService의 구현 객체가 스레드풀이다.

 

 스레드풀의 생성

스레드풀, 즉 ExecutorService의 구현객체를 만드는 Executors 클래스의 정적메소드는 아래 2가지가 있다.

  • newCachedThreadPool()
  • newFixedThreadPool(int nThreads)

newCachedThreadPool()은 스레드의 개수를 정적으로 제한하지 않는다. 초기 0개에서 시작하여 실행되는 스레드의 개수가 늘어남에 따라 스레드풀의 스레드의 개수도 늘어난다. 반대로 실행되는 스레드가 줄어들면 스레드 풀의 스레드 개수도 줄어든다. 최대 int 값의 최댓값까지 가질 수 있지만 실제로는 운영체제의 사정에 따라 달라진다.

ExecutorService executorService = Executors.newCachedThreadPool();

 

newFixedThreadPool(int nThreads)는 스레드의 개수를 nThreads로 고정한다. 즉, 실행되는 스레드가 많든 적든 항상 스레드의 개수는 nThreads이다. 

ExecutorService executorService = Executors.newFixedThreadPool(
	Runtime.getRuntime().availableProcessors()	// cpu의 코어수 만큼 생성함
);

스레드의 개수를 동적으로 관리하고 싶을때는 newCachedThread, 정적으로 관리하고 싶을때는 newFixedThreadPool 이라고 생각하면 쉽다.

 

Executors 클래스의 정적 메소드를 이용하지 않고, 직접 스레드풀을 생성하고 싶을 때는 ThreadPoolExecutor 객체를 생성하면된다.

ExecutorService threadPool = new ThreadPoolExecutor(
	3,	// 코어 스레드의 개수
    	100,	// 최대 스레드의 개수
        120L,	// 놀고 있는 시간
        TimeUint.SECONDS,	// 놀고 있는 시간 단위
        new SynchronousQueue<Runnable>()	// 작업 큐
);

 

스레드풀의 종료

스레드풀의 스레드는 main 스레드의 데몬 스레드가 아니므로 main 스레드가 종료되더라도 남아있게 된다. 그러므로 스레드풀을 직접 종료 시켜주어야 하는데 스레드풀을 종료하는 2가지가 있다.

  • shutdown() : 남아있는 작업을 마무리하고 스레드풀을 종료한다.
  • shutdownNow() : 남아있는 작업과 무관하게 스레드풀을 즉시 종료한다.
executorService.shutdown();
// or
executorService.shutdownNow();