public interface Executor {
void execute(Runnable command);
}
public interface ExecutorService extends Executor, AutoCloseable {
<T> Future<T> submit(Callable<T> task);
@Override
default void close(){...}
}
new ThreadPoolExecutor()를 통해 생성 가능corePoolSize : 스레드 풀에서 관리되는 기본 스레드의 수maximumPoolsize : 스레드 풀에서 관리되는 최대 스레드 수keepAliveTime, TimeUnit unit : 기본 스레드 수를 초과해서 만들어진 스레드가 생존할 수 있는 대기 시간BlockingQueue workQueue: 작업읍 보관할 블로킹 큐ExecutorService executorService = new ThreadPoolExecutor(2, 2, 0, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>())ExecutorService executorService = new ThreadPoolExecutor(2, 2, 0, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>())
Main 스레드가 executorService.execute(task1 ~ task4) 호출
작업 진행
작업이 완료되면 스레드 풀에 스레드를 반납 (WATING 상태)
작업 종료
close()는 자바 19부터 지원되는 메서드, 이전 버전은shutdown()호출 --> 둘의 차이 존재
newSingleThreadPool() : 단일 스레드 풀 전략newFixedThreadPool(nThreads) : 고정 스레드 풀 전략newCachedThreadPool() : 캐시 스레드 풀 전략newSingleThreadPool()new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILISECONDS, new LinkedBlockingQueue<Runnable>())
LinkedBlockingQueue)newFixedThreadPool(nThreads)new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILISECONDS, new LinkedBlockingQueue<Runnable>())
nThreads만큼의 기본 스레드를 생성LinkedBlockingQueue)new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());
SynchronousQueue)위 상황을 아래와 같이 세분화 전략을 사용하면 어느 정도 대응이 가능
new ThreadPoolExecutor(100, 200, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(1000));
ThreadPoolExecutor는 작업을 거절하는 다양한 정책을 제공
RejectedExecutionException 발생 (기본 정책)해당 정책은
shutdown()호출 후 거절된 작업에도 같은 정책이 적용됨
public interface RejectedExecutionHandler {
void rejectedExecution(Runnable r, ThreadPoolExecutor executor);
}
ThreadPoolExecutor가 거절 하는 상황 발생 시 해당 클래스를 상속받은 구현체에 정의된 정책을 사용한다.ThreadPoolExecutor의 마지막 인자에 해당 인터페이스의 구현체를 넣어 사용ExecutorService es = new ThreadPoolExecutor(1,1,0, TimeUnit.SECONDS,
new SynchronousQueue<>(), new ThreadPoolExecutor.AbortPolicy());
RejectedExecutionException 을 던짐 AbortPolicy는 RejectedExecutionHandler의 구현체public static class AbortPolicy implements RejectedExecutionHandler {
public void rejectedExectuion(Runnable r, ThreadPoolExecutor e) {
throw new RejectedExecutionException("Task "+ r.toStrig() + " rejected from " + e.toString());
}
}
ExecutorService es = new ThreadPoolExecutor(1,1,0, TimeUnit.SECONDS,
new SynchronousQueue<>(), new ThreadPoolExecutor.DiscardPolicy());
DiscardPolicy는 RejectedExecutionHandler의 구현체public static class DiscardPolicy implements RejectedExecutionHandler {
public void rejectedExectuion(Runnable r, ThreadPoolExecutor e) {
// empty <-- 비어있음
}
}
ExecutorService es = new ThreadPoolExecutor(1,1,0, TimeUnit.SECONDS,
new SynchronousQueue<>(), new ThreadPoolExecutor.CallerRunsPolicy());
CallerRunsPolicy는 RejectedExecutionHandler의 구현체public static class CallerRunsPolicy implements RejectedExecutionHandler {
public void rejectedExectuion(Runnable r, ThreadPoolExecutor e) {
if(!e.isShutdown()){ // shutDown() 호출 시 호출한 스레드가 실행 되지 않도록 if()에서 호출
r.run(); // 호출한 스레드가 직접 실행
}
}
}
ThreadPoolExecutor를 shutdown()하면 이후 요청 하는 작업이 거절되는데 이때도 같은 정책이 적용됨CallerRunsPolicy 정책은 shutDown() 이후에도 작업을 수행함shutdown() 조건을 체크해서 이 경우에는 작업을 수행하지 않도록 해야함ExecutorService es = new ThreadPoolExecutor(1,1,0, TimeUnit.SECONDS,
new SynchronousQueue<>(), new ThreadPoolExecutor.MyRejectedExecutionHandler());
RejectedExecutionHandler 인터페이스를 구현하여 자신만의 거절 처리 전략 정의public static class MyRejectedExecutionHandler implements RejectedExecutionHandler {
static AtmoicInteger count = new AtomicInteger(0);
public void rejectedExectuion(Runnable r, ThreadPoolExecutor e) {
int i = count.incrementAndGet();
log("[경고] 거절된 누적 작업 수: " + i);
}
}