목차

Java ExecutorService

최적의 쓰레드 풀 수

Java Concurrency in Practice에 나오는 내용

N쓰레드 = N씨피유 * U씨피유 * (1 + W/C)

Basic ExecutorService shutdown Pattern

executorService.shutdown();
try {
    if (!executorService.awaitTermination(800, TimeUnit.MILLISECONDS)) {
        executorService.shutdownNow();
    } 
} catch (InterruptedException e) {
    executorService.shutdownNow();
}
 

CahcedThreadPool

ExecutorService executorService = Executors.newCachedThreadPool();

ScheduledExecutor

ExecutorService vs. Fork/Join

ExecutorService 주의점

ThreadPoolExecutor

A ThreadPoolExecutor will automatically adjust the pool size (see getPoolSize()) according to the bounds set by corePoolSize (see getCorePoolSize()) and maximumPoolSize (see getMaximumPoolSize()). When a new task is submitted in method execute(Runnable), and fewer than corePoolSize threads are running, a new thread is created to handle the request, even if other worker threads are idle. If there are more than corePoolSize but less than maximumPoolSize threads running, a new thread will be created only if the queue is full. By setting corePoolSize and maximumPoolSize the same, you create a fixed-size thread pool. By setting maximumPoolSize to an essentially unbounded value such as Integer.MAX_VALUE, you allow the pool to accommodate an arbitrary number of concurrent tasks. Most typically, core and maximum pool sizes are set only upon construction, but they may also be changed dynamically using setCorePoolSize(int) and setMaximumPoolSize(int).
corePoolSize 만큼의 쓰레드가 만들어져 있으면, 그 다음 쓰레드는 queueCapacity만큼 큐에 쌓여 있다가 corePool로 실행이 인입된다. 따라서 corePoolSize가 작고 queueCapacity가 매우 크면 queue가 꽉차기 전까지는 실제로 쓰레드 풀이 확장되지 않고 계속해서 corePool 만 재사용하게 된다.

ExecutorCompletionService

final ExecutorService pool = Executors.newFixedThreadPool(5);
 
// 응답 타입(String) 명시 필요
final ExecutorCompletionService<String> completionService = new ExecutorCompletionService<>(pool);
 
for (final String site : topSites) {
    completionService.submit(new Callable<String>() {
        @Override
        public String call() throws Exception {
            return IOUtils.toString(new URL("http://" + site), StandardCharsets.UTF_8);
        }
    });
}
 
// submit 한 갯수가 정확해야한다.
for(int i = 0; i < topSites.size(); ++i) {
    final Future<String> future = completionService.take(); // 먼저 실행되는 대로 바로 리턴
    try {
        final String content = future.get();
        //...process contents
    } catch (ExecutionException e) {
        log.warn("Error while downloading", e.getCause());
    }
}