[Effective Java] 스레드 그룹보다는 실행자와 작업을 사용하자. |
-
자바 1.5 배포판 이후에 java.util.concurrent 패키지가 추가되었다.
여기에는 실행자 프레임워크(Executor Framework) 가 포함되어 있다.
이 녀석을 사용하면 Work queue 를 쉽게 관리할 수 있다.
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.execute(runnable);
executor.shutdown(); // 추가된 task 들의 실행은 보장한다. shutdownNow() 도 있다.
위와 같은 간단한 코드로 쉽게 queue 를 만들어 실행시킬 수 있고,
shutdown 시킬 수 있다.
-
ExecutorService 를 사용하면 정말 많은 일을 할 수 있다.
특정 작업이 완료되기를 기다릴 수 있고,
어떤 컬렉션의 일부 또는 모든 요소에 대한 작업이 완료되기를 기다릴 수 있으며 ( invokeAny, invokeAll - 이들은 collection 을 전달하고, 그 중 한개 혹은 전부가 끝날때까지 기다리는 기능을 한다. )
실행자 서비스의 종료가 완료되기를 기다릴 수 있고( awaitTermination )
작업이 하나씩 끝나는대로 그 결과를 받아 볼 수 있다.(ExecutorCompletionService - Callable 과 연동 )
-
ThreadPoolExecutor 클래스를 직접 사용하여 더 세부적인 사항을 설정하여 사용할 수도 있다.
-
특정 어플에 적합한 실행자 서비스를 선택하기는 쉽지 않다.
만일 작은 규모의 프로그램이나 가볍게 적재되는 서버를 작성하면,
일반적으로 Executors.newCachedThreadPool 메소드를 사용해서 반환된 실행자 서비스를 사용하는 것이 좋다.
CachedThreadPool 은 queue 에 넣지 않고 바로 스레드로 넘겨 실행한다.
만일 가용할 스레드가 없으면 새로운 스레드가 생성된다.
따라서 과도하게 적재된 업무 서버에는 Executors.newFixedThread 를 사용해서 반환된 실행자 서비스(정해진 수의 스레드를 갖는 풀을 제공)을 사용하거나, 스레드 제어를 극대화 하기 위해 ThreadPoolExecutor 클래스를 직접 사용하는 것이 좋다.
-
작업에는 두 종류가 있다.
Runnable 과 Callable(값을 반환하는 것이 Runnable 과 다름).
그리고 작업을 실행하는 일반적인 메커니즘이 executor service 이다.
-
ScheduledThreadPoolExecutor 도 있다.
Timer 가 사용하기는 더 쉬운 반면, 유연성은 ScheduledThreadPoolExecutor 가 훨씬 좋다.
Timer 는 작업 실행을 위해 하나의 스레드만 사용하므로 오래 동안 실행하는 작업이 있을 경우 시간 측정의 정확도가 떨어질 수 있다. 또한 catch 안 된 예외를 던지면 Timer 가 중단된다.
ScheduledThreadPoolExecutor 는 다중 스레드를 지원하고, unchecked 예외를 던지는 작업을 복구한다.
'프로그래밍 놀이터 > 디자인 패턴, 리펙토링' 카테고리의 다른 글
[Effective Java] 스레드 안전을 문서화 하자. (0) | 2017.03.14 |
---|---|
[Effective Java] wait 와 notify 대신 동시성 유틸리티를 사용하자. (0) | 2017.03.13 |
[Effective Java] 지나친 동기화는 피하자 (0) | 2017.03.09 |
[Effective Java] 공유하는 가변 데이터에 접근 시 동기화하자. (0) | 2017.03.07 |
[Effective Java] 예외를 묵살하지 말자. (0) | 2017.03.06 |
댓글