본문 바로가기

자바

[스레드] 10. 스레드풀(1) ExecutorService

스레드 폭증

- 병렬 작업 처리가 많아지면 스레드의 개수가 증가

- 스레드 생성과 스케쥴링으로 인해 cpu가 바빠지고, 메모리 사용량이 늘어난다.

- 따라서 애플리케이션 성능 급격히 저하됨.

 

스레드 풀(Thread pool)

- 작업 처리에 사용되는 스레드를 제한된 개수만큼 미리 생성

- 작업 큐(Queue)에 들어오는 작업들을 하나씩 스레드가 맡아 처리

- 작업 처리가 끝난 스레드는 작업 결과를 애플리케이션으로 전달

- 스레드는 다시 작업큐에서 새로운 작업을 가져와 처리

 

ExecutorService 인터페이스와 Executors 클래스

- 스레드풀을 생성하고 사용할 수 있도록 java.util.concurrent 패키지에서 제공

- Executors의 정적 메소드를 이용해서 ExecutorService 구현 객체 생성

- 스레드 풀 = ExecutorService 객체

 

스레드풀 생성

- 다음 두가지 메소드 중 하나로 간편 생성

newCachedThreadPool()

초기스레드수: 0

코어 스레드수 : 0

최대 스레드 수: Integer.MAX_VALUE

int값이 가질 수 있는 최대 값만큼 스레드가 추가되나, 운영체제의 상황에 따라 달라짐.

1개 이상의 스레드가 추가되었을 경우 60초 동안 추가된 스레드가 아무 작업을 하지 않으면 추가된 스레드를 종료하고 풀에서 제거.

ExecutorService executorService = Executors.newCachedThreadPool();

newFixedThreadPool(int nThreads)

초기스레드 수 : 0

코어 스레드수 : nThreads

최대 스레드 수 : nThreads

코어 스레드개수와 최대 스레드가 개수가 매개값으로 준 nThread이다.

스레드가 작업을 처리하지 않고 놀고 있더라도 스레드갯수가 줄지 않는다.

ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());

 

ThreadPoolExecutor 를 이용한 직접 생성

- newCachedThreadPool()과 newFixedThreadPool(int nThreads)가 내부적으로 생성

- 스레드의 수를 자동을 관리하고 싶을 경우 직접 생성해서 사용

 

ex)

코어 스레드 개수가 3, 최대 스레드 개수가 100인 스레드풀을 생성

3개를 제외한 나머지 추가된 스레드가 120초 동안 놀고 있을 경우

해당 스레드를 제거해서 스레드 수를 관리

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

 

스레드 풀 종료

스레드풀의 스레드는 기본적으로 데몬 스레드가 아님

main 스레드가 종료되더라도 스레드풀의 스레드는 작업을 처리하기 위해 계속 실행되므로 애플리케이션은 종료x

따라서 스레드풀을 종료해서 모든 스레드를 종료시켜야 함.

 

스레드풀 종료 메소드

shutdown()

현재 처리중인 작업뿐만 아니라 작업큐에 대기하고 있는 모든 작업을 처리한 뒤에 스레드풀을 종료시킨다.

List<Runnable> shutDownNow()

현재 작업처리 중인 스레드를 interrupt 해서 작업 중지를 시도하고 스레드풀을 종료시킨다. 리턴값은 작업큐에 있는 미처리된 작업(Runnable)의 목록이다.

boolean awaitTermination(long timeout, TimeUnit unit)

shutdown() 메소드 호출 이후, 모든 작업 처리를 timeout 시간 내에 완료하면 true를 리턴하고, 완료하지 모샇면 작업 처리 중인 스레드를 interrupt 하고 false 리턴.

 

작업생성

- 하나의 작업은 Runnable 또는 Callable 객체로 표현

- Runnable과 Callable 의 차이점

작업 처리 완료 후 리턴값이 있냐 없냐 차이.

- 스레드풀에서 작업처리

작업 큐에서 Runnable 또는 Callable 객체를 가져와 스레드로 하여금 run()과 call() 메소드를 실행토록 하는 것.

 

 

작업 처리 요청

ExecutorService 의 작업 큐에 Runnable또는 Callable 객체를 넣는 행위

작업 처리 요청을 위해 ExecutorService는 다음 두가지 종류의 메소드제공

void execute(Runnable command)

- Runnable 을 작업큐에 저장

- 작업 처리 결과 리턴x

Future<?> submit(Runnable task)

Future<V> submit(Runnable task, V result)

Future<V> submit(Callable<V> task)

- Runnable 또는 Callable을 작업큐에 저장

- 리턴된 Future를 통해 작업 처리 결과 return.

 

작업 처리 도중 예외가 발생할 경우

* execute(():

스레드가 종료되고 해당 스레드는 제거됨.

따라서 스레드풀은 다른 작업 처리를 위해 새로운 스레드 생성

* submit():

스레드가 종료되지않고 다음 작업을 위해 재사용.

'자바' 카테고리의 다른 글

[스레드] 12. 스레드풀(3)  (0) 2022.05.07
[스레드] 11. 스레드풀(2)  (0) 2022.05.05
[스레드] 9. 스레드 그룹  (0) 2022.05.01
[스레드] 8. 데몬 스레드  (0) 2022.05.01
[스레드] 7. 스레드 상태제어  (0) 2022.04.24