Java

[Java] 스레드 풀(ThreadPool) 이란? ThreadPool 종류

김맷돌 2024. 3. 12. 13:14
반응형

ThreadPool 이란?

100개의 작업을 비동기적으로 처리해야할 때에, 어떤 방법을 떠올릴 수 있을까? 간단히 스레드를 100개 만들어 처리하는 코드를 작성해보자.

public class ExecutorExample {
		
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Thread thread = new Thread(new Task());
        thread.start();

        System.out.println(Thread.currentThread() + " hello");
    }

    static class Task implements Runnable {

        @Override
        public void run() {
            try {
                Thread.sleep(2000L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(Thread.currentThread() + " world");
        }
    }
}

이와 같이 100개의 작업을 스레드 100개를 생성해 처리하게 되면 굉장히 많은 시스템 리소스를 사용하게 된다. 그렇다면 스레드를 100개를 사용하지 않고 100개의 작업을 비동기적으로 처리할 수는 없을까?

 

ThreadPool을 사용하면 가능하다.

public class ExecutorExample {
		
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 10개의 스레드를 가지는 스레드 풀 생성
        ExecutorService service = Executors.newFixedThreadPool(10);
        
        for (int i = 0; i < 100; i++) {
            service.submit(new Task());
        }

        System.out.println(Thread.currentThread() + " hello");
    }

    static class Task implements Runnable {

        @Override
        public void run() {
            try {
                Thread.sleep(2000L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(Thread.currentThread() + " world");
        }
    }
}

10개의 스레드를 가지는 스레드 풀을 생성함으로써, 10개의 스레드만을 가지고 100개의 작업을 처리할 수 있게 되었다. 이 때 스레드 풀이 가질 스레드의 개수를 적절히 설정하는 것이 중요하다.

 

스레드의 개수를 고려하기 위해서는 현재 처리하려는 작업이 어떤 작업인지를 인지해야 한다. CPU 사용량이 많은 작업일 경우에는 CPU 개수만큼만 스레드를 생성하는 것이 적절하다. 스레드를 CPU 개수 이상으로 늘린다고 해도 CPU 개수만큼만 처리가 가능하기 때문이다. 사용중인 CPU 개수는 아래 코드를 이용하여 알아낼 수 있다.

int numberOfCpu = Runtime.getRuntime().availableProcessors();

 

반대로, I/O 작업이 잦은 경우에는 스레드 개수를 늘릴 필요가 있다. I/O 작업에서 딜레이가 발생할 경우 CPU가 idle해질 수 있기 때문이다. 얼마나 많이 잡아야 하는가에는 정답이 없다. 지속적인 성능 튜닝을 통해 스레드 개수의 적절한 조정이 필요하다.

 

 

ThreadPool 종류

  • newFixedThreadPool
    • 주어진 스레드 개수만큼 생성하고 그 수를 유지한다.
    • 생성된 스레드 중 일부가 종료되었으면 스레드를 다시 생성한다.
    • 내부적으로 BlockingQueue를 사용하여 concurrency를 보장한다.
      • ArrayList나 HashMap같은 일반적인 컬렉션의 경우 concurrency가 보장되지 않아 여러 스레드가 동시에 접근할 경우 ConcurrentModificationException이 발생할 수 있다.
  • newCachedThreadPool
    • 필요한 만큼 스레드를 생성하여 사용한다.
    • 최대 Integer.MAX_VALUE 만큼 생성한다.
    • 작업이 많아지면 그만큼 스레드를 추가생성하므로 자원을 많이 사용하게 된다.
  • newSingleThreadPool
    • 스레드를 하나만 생성하여 사용한다.
  • newScheduledThreadPool
    • 특정 시간 이후 또는 주기적인 작업을 해야하는 스레드가 필요할 경우 사용한다.
반응형

'Java' 카테고리의 다른 글

[Java] SLF4J로 예외 로깅하기  (1) 2024.02.27
[Java] SerialVersionUID 란?  (0) 2024.02.20
[Java] Unchecked Exception에 관한 논쟁  (0) 2024.02.01