수색…


소개

Java의 Executor 인터페이스는 스레드 사용, 스케줄링 등에 대한 세부 정보를 포함하여 각 작업이 어떻게 실행될 것인지에 대한 메커니즘에서 작업 제출을 분리하는 방법을 제공합니다. 일반적으로 명시 적으로 스레드를 작성하는 대신 Executor가 사용됩니다. Executors를 사용하면 개발자는 프로그램의 작업 실행 정책을 쉽게 조정할 수 있도록 코드를 크게 재 작성할 필요가 없습니다.

비고

함정

  • 반복 실행을 위해 작업을 예약 할 때 사용되는 ScheduledExecutorService에 따라 작업을 실행하면 처리되지 않는 예외가 발생할 경우 이후 실행이 일시 중단 될 수 있습니다. ScheduledExecutorService를 참조하십시오 .

화재와 잊기 - 실행 가능한 작업

Executors는 java.lang.Runnable 을 받아들입니다.이 java.lang.Runnable 에는 (다른 스레드에서 실행될 수있는 (계산적으로 또는 다른 방식으로 실행 시간이 길거나 무거운) 코드가 들어 있습니다.

사용법은 다음과 같습니다.

Executor exec = anExecutor;
exec.execute(new Runnable() {
    @Override public void run() {
        //offloaded work, no need to get result back
    }
});

이 실행 프로그램을 사용하면 계산 된 값을 다시 얻을 수있는 방법이 없습니다.
Java 8에서는 lambda를 사용하여 코드 예제를 단축 할 수 있습니다.

Java SE 8
Executor exec = anExecutor;
exec.execute(() -> {
    //offloaded work, no need to get result back
});

ThreadPoolExecutor

일반적으로 사용되는 Executor는 ThreadPoolExecutor 이며, ThreadPoolExecutor 는 스레드 처리를 담당합니다. 실행해야 할 작업이 많지 않은 경우 실행 프로그램이 항상 유지해야하는 최소 크기의 스레드 (코어 크기라고 함)와 풀이 커질 수있는 최대 스레드 크기를 구성 할 수 있습니다. 작업 부하가 감소하면 풀은 최소 크기에 도달 할 때까지 스레드 수를 천천히 줄입니다.

ThreadPoolExecutor pool = new ThreadPoolExecutor(
    1,                                     // keep at least one thread ready, 
                                           // even if no Runnables are executed
    5,                                     // at most five Runnables/Threads
                                           // executed in parallel
    1, TimeUnit.MINUTES,                   // idle Threads terminated after one
                                           // minute, when min Pool size exceeded
    new ArrayBlockingQueue<Runnable>(10)); // outstanding Runnables are kept here

pool.execute(new Runnable() {
    @Override public void run() {
        //code to run
    }
});

주 안 바운드 큐로 ThreadPoolExecutor 를 구성하면, 큐가 가득 찬 경우에만 새 스레드가 작성되므로 스레드 수는 corePoolSize 초과하지 않습니다.

모든 파라미터를 가지는 ThreadPoolExecutor

ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, 
TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory,
RejectedExecutionHandler handler)

JavaDoc에서

corePoolSize 이상으로 실행 중의 maximumPoolSize보다 작은 스레드가있는 경우, 큐가 가득 찬 경우에만 새 스레드가 작성됩니다.

장점 :

  1. BlockingQueue 크기를 제어하고 메모리 부족 시나리오를 피할 수 있습니다. 제한된 제한된 대기열 크기로 인해 응용 프로그램 성능이 저하되지 않습니다.

  2. 기존의 Rejection Handler 정책을 사용하거나 새로운 Rejection Handler 정책을 만들 수 있습니다.

    1. 기본 ThreadPoolExecutor.AbortPolicy에서 처리기는 거부시 런타임 RejectedExecutionException을 발생시킵니다.

    2. ThreadPoolExecutor.CallerRunsPolicy 에서는 execute 자체를 호출하는 스레드가 작업을 실행합니다. 이는 새로운 작업이 제출되는 속도를 늦출 수있는 간단한 피드백 제어 메커니즘을 제공합니다.

    3. ThreadPoolExecutor.DiscardPolicy 에서는, 실행할 수없는 태스크는 간단하게 삭제됩니다.

    4. ThreadPoolExecutor.DiscardOldestPolicy 에서 executor가 종료되지 않은 경우 작업 대기열의 헤드에있는 작업이 삭제 된 다음 실행이 다시 시도됩니다 (다시 실패 할 수 있으므로 반복 될 수 있음).

  3. 사용자 정의 ThreadFactory 를 구성 할 수 있으므로 유용합니다.

    1. 보다 이해하기 쉬운 스레드 이름을 설정하려면
    2. 스레드 데몬 상태를 설정하려면
    3. 스레드 우선 순위를 설정하려면

다음 은 ThreadPoolExecutor를 사용하는 방법의 예입니다.

계산에서 값 검색 - 호출 가능

계산 결과가 나중에 필요한 반환 값을 생성하면 간단한 Runnable 작업으로는 충분하지 않습니다. 이러한 경우 ExecutorService.submit( Callable <T>) 을 사용하여 실행 완료 후 값을 반환 할 수 있습니다.

서비스는 작업 실행 결과를 검색하는 데 사용할 수있는 Future 를 반환합니다.

// Submit a callable for execution
ExecutorService pool = anExecutorService;
Future<Integer> future = pool.submit(new Callable<Integer>() {
    @Override public Integer call() {
        //do some computation
        return new Random().nextInt();
    }
});    
// ... perform other tasks while future is executed in a different thread

미래의 결과를 얻으려면 future.get() 호출 future.get()

  • 미래가 끝날 때까지 무한정 기다려 결과를 얻습니다.

      try {
          // Blocks current thread until future is completed
          Integer result = future.get(); 
      catch (InterruptedException || ExecutionException e) {
          // handle appropriately
      }
    
  • 미래가 끝날 때까지 기다리십시오. 그러나 지정된 시간보다 길어서는 안됩니다.

      try {
          // Blocks current thread for a maximum of 500 milliseconds.
          // If the future finishes before that, result is returned,
          // otherwise TimeoutException is thrown.
          Integer result = future.get(500, TimeUnit.MILLISECONDS); 
      catch (InterruptedException || ExecutionException || TimeoutException e) {
          // handle appropriately
      }
    

예약되거나 실행중인 작업의 결과가 더 이상 필요하지 않으면 Future.cancel(boolean) 을 호출하여 취소 할 수 있습니다.

  • cancel(false) 호출하면 실행될 작업 대기열에서 작업이 제거됩니다.
  • cancel(true) 호출하면 현재 실행중인 작업 중단됩니다.

지연되거나 반복적으로 일정한 시간에 작업 실행 예약

ScheduledExecutorService 클래스는 여러 가지 방법으로 단일 또는 반복 작업을 예약하는 메서드를 제공합니다. 다음 코드 샘플에서는 pool 이 다음과 같이 선언되고 초기화되었다고 가정합니다.

ScheduledExecutorService pool = Executors.newScheduledThreadPool(2);

일반 ExecutorService 메소드 외에도 ScheduledExecutorService API는 작업을 예약하고 ScheduledFuture 객체를 반환하는 4 가지 메소드를 추가합니다. 후자는 결과를 검색하고 (일부 경우) 작업을 취소하는 데 사용할 수 있습니다.

고정 지연 후 작업 시작

다음 예는 10 분 후에 작업을 시작하도록 예약합니다.

ScheduledFuture<Integer> future = pool.schedule(new Callable<>() {
        @Override public Integer call() {
            // do something
            return 42;
        }
    }, 
    10, TimeUnit.MINUTES);

고정 속도로 작업 시작

다음 예는 10 분 후에 작업을 시작한 다음 1 분에 한 번씩 반복적으로 작업을 예약합니다.

ScheduledFuture<?> future = pool.scheduleAtFixedRate(new Runnable() {
        @Override public void run() {
            // do something
        }
    }, 
    10, 1, TimeUnit.MINUTES);

작업 실행은 pool 종료되거나, future 가 취소되거나, 작업 중 하나에서 예외가 발생할 때까지 일정에 따라 계속됩니다.

주어진 scheduledAtFixedRate 호출에 의해 스케줄 된 태스크가 시간에 중복되지 않는다는 것이 보장됩니다. 작업이 지정된 기간보다 오래 걸리면 다음 작업 실행과 후속 작업 실행이 늦게 시작될 수 있습니다.

고정 지연으로 작업 시작

다음 예는 작업이 10 분 후에 시작하도록 스케쥴 한 다음 하나의 작업 종료와 다음 시작 사이에 1 분의 지연으로 반복적으로 스케줄합니다.

ScheduledFuture<?> future = pool.scheduleWithFixedDelay(new Runnable() {
        @Override public void run() {
            // do something
        }
    }, 
    10, 1, TimeUnit.MINUTES);

작업 실행은 pool 종료되거나, future 가 취소되거나, 작업 중 하나에서 예외가 발생할 때까지 일정에 따라 계속됩니다.

거절 된 명령 처리

만약

  1. 종료 Executor에 작업을 제출하려고 시도하거나
  2. 대기열은 포화 상태 (바운드 상태의 객체에 대해서만 가능)이며 최대 스레드 수에 도달했습니다.

RejectedExecutionHandler.rejectedExecution(Runnable, ThreadPoolExecutor) 가 불려갑니다.

기본 동작은 호출자에게 Throw 된 RejectedExecutionException을 가져 오는 것입니다. 그러나 사용할 수있는 미리 정의 된 비헤이비어가 더 많이 있습니다.

  • ThreadPoolExecutor.AbortPolicy (디폴트에서는, REE를 슬로우합니다)
  • ThreadPoolExecutor.CallerRunsPolicy (호출자의 스레드에서 작업 실행 - 차단 )
  • ThreadPoolExecutor.DiscardPolicy (태스크를 통지없이 파기)
  • ThreadPoolExecutor.DiscardOldestPolicy (대기열에서 가장 오래된 작업을 자동 삭제하고 새 작업의 실행을 다시 시도)

ThreadPool 생성자 중 하나를 사용하여 설정할 수 있습니다.

public ThreadPoolExecutor(int corePoolSize,
                      int maximumPoolSize,
                      long keepAliveTime,
                      TimeUnit unit,
                      BlockingQueue<Runnable> workQueue,
                      RejectedExecutionHandler handler) // <--

public ThreadPoolExecutor(int corePoolSize,
                      int maximumPoolSize,
                      long keepAliveTime,
                      TimeUnit unit,
                      BlockingQueue<Runnable> workQueue,
                      ThreadFactory threadFactory,
                      RejectedExecutionHandler handler) // <--

RejectedExecutionHandler 인터페이스를 확장하여 자신 만의 동작을 구현할 수도 있습니다.

void rejectedExecution(Runnable r, ThreadPoolExecutor executor)

submit () vs execute () 예외 처리 차이

일반적으로 execute () 명령어는 fire와 forget call (결과를 분석 할 필요없이)에 사용되며 submit () 명령어는 Future 객체의 결과를 분석하기 위해 사용됩니다.

이 두 명령 사이의 예외 처리 메커니즘의 주요 차이점을 알아야합니다.

submit ()의 예외는 프레임 워크가 잡아 내지 않으면 프레임 워크에 의해 삼켜진다.

차이를 이해하는 코드 예제 :

사례 1 : Exception을보고하는 execute () 명령으로 Runnable을 제출하십시오.

import java.util.concurrent.*;
import java.util.*;

public class ExecuteSubmitDemo {
    public ExecuteSubmitDemo() {
        System.out.println("creating service");
        ExecutorService service = Executors.newFixedThreadPool(2);
        //ExtendedExecutor service = new ExtendedExecutor();
        for (int i = 0; i < 2; i++){
            service.execute(new Runnable(){
                 public void run(){
                    int a = 4, b = 0;
                    System.out.println("a and b=" + a + ":" + b);
                    System.out.println("a/b:" + (a / b));
                    System.out.println("Thread Name in Runnable after divide by zero:"+Thread.currentThread().getName());
                 }
            });
        }
        service.shutdown();
    }
    public static void main(String args[]){
        ExecuteSubmitDemo demo = new ExecuteSubmitDemo();
    }
}

class ExtendedExecutor extends ThreadPoolExecutor {

   public ExtendedExecutor() { 
       super(1, 1, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(100));
   }
   // ...
   protected void afterExecute(Runnable r, Throwable t) {
     super.afterExecute(r, t);
     if (t == null && r instanceof Future<?>) {
       try {
         Object result = ((Future<?>) r).get();
       } catch (CancellationException ce) {
           t = ce;
       } catch (ExecutionException ee) {
           t = ee.getCause();
       } catch (InterruptedException ie) {
           Thread.currentThread().interrupt(); // ignore/reset
       }
     }
     if (t != null)
       System.out.println(t);
   }
 }

산출:

creating service
a and b=4:0
a and b=4:0
Exception in thread "pool-1-thread-1" Exception in thread "pool-1-thread-2" java.lang.ArithmeticException: / by zero
        at ExecuteSubmitDemo$1.run(ExecuteSubmitDemo.java:15)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
        at java.lang.Thread.run(Thread.java:744)
java.lang.ArithmeticException: / by zero
        at ExecuteSubmitDemo$1.run(ExecuteSubmitDemo.java:15)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
        at java.lang.Thread.run(Thread.java:744)

사례 2 : execute ()를 submit ()으로 대체하십시오. service.submit(new Runnable(){ 이 경우 run () 메소드가 명시 적으로 catch하지 않았으므로 프레임 워크에서 예외를 삼켰습니다.

산출:

creating service
a and b=4:0
a and b=4:0

사례 3 : newFixedThreadPool을 ExtendedExecutor로 변경

//ExecutorService service = Executors.newFixedThreadPool(2);
 ExtendedExecutor service = new ExtendedExecutor(); 

산출:

creating service
a and b=4:0
java.lang.ArithmeticException: / by zero
a and b=4:0
java.lang.ArithmeticException: / by zero

두 가지 주제를 다룰 수있는이 예제를 보여주었습니다. 사용자 정의 ThreadPoolExecutor를 사용하고 Exectpion을 사용자 정의 ThreadPoolExecutor로 처리합니다.

위의 다른 간단한 해결책 : 일반적인 ExecutorService 및 submit 명령을 사용하는 경우 submit () 명령 호출에서 Future 객체를 가져오고 Future ()에서는 get () API를 호출합니다. afterExecute 메서드 구현에서 인용 된 세 가지 예외를 잡으십시오. 이 접근법에 대한 커스텀 ThreadPoolExecutor의 장점 : 예외 처리 메커니즘을 사용자 정의 ThreadPoolExecutor 한 곳에서만 처리해야합니다.

동시성 구조의 다른 유형에 대한 사용 사례

  1. ExecutorService

    ExecutorService executor = Executors.newFixedThreadPool(50);

    간단하고 사용하기 쉽습니다. ThreadPoolExecutor 상세 수준을 숨 깁니다.

    Callable/Runnable 작업의 수가 적을 때 무제한 대기열의 작업을 쌓아도 메모리가 증가하지 않고 시스템 성능이 저하 될 때이 방법을 선호합니다. CPU/Memory 제약이있는 경우 작업 RejectedExecutionHandler 를 처리하기 위해 용량 제약 & RejectedExecutionHandler 와 함께 ThreadPoolExecutor 를 사용하는 것을 선호합니다.

  2. CountDownLatch

    CountDownLatch 는 주어진 카운트로 초기화됩니다. 이 수는 countDown() 메소드를 호출하여 감소합니다. 이 개수가 0이 될 때까지 대기하는 스레드는 await() 메소드 중 하나를 호출 할 수 await() . await() 호출하면 카운트가 0이 될 때까지 스레드가 차단됩니다. 이 클래스는, Java thread가, 다른 thread 세트가 태스크를 완료 할 때까지 대기 할 수 있도록 (듯이)합니다.

    사용 사례:

    1. 최대 병렬 처리 달성하기 : 때로는 최대한의 병렬 처리를 달성하기 위해 동시에 여러 스레드를 시작하려고합니다

    2. 실행을 시작하기 전에 N 개의 스레드가 완료 될 때까지 기다리십시오.

    3. 교착 상태 감지.

  1. ThreadPoolExecutor : 더 많은 제어 기능을 제공합니다. 응용 프로그램이 대기중인 Runnable / Callable 작업의 수로 제한되면 최대 용량을 설정하여 제한된 대기열을 사용할 수 있습니다. 큐가 최대 용량에 도달하면 RejectionHandler를 정의 할 수 있습니다. Java는 네 가지 유형의 RejectedExecutionHandler 정책을 제공합니다.

    1. ThreadPoolExecutor.AbortPolicy , 처리기는 거부시 런타임 RejectedExecutionException을 throw합니다.

    2. ThreadPoolExecutor.CallerRunsPolicy`를 실행하면 execute 자체를 호출하는 스레드가 작업을 실행합니다. 이는 새로운 작업이 제출되는 속도를 늦출 수있는 간단한 피드백 제어 메커니즘을 제공합니다.

    3. ThreadPoolExecutor.DiscardPolicy 에서는, 실행할 수없는 태스크는 간단하게 삭제됩니다.

    4. ThreadPoolExecutor.DiscardOldestPolicy 는 executor가 종료되지 않은 경우 작업 큐의 헤드에있는 작업을 삭제 한 다음 실행을 다시 시도합니다 (다시 실패 할 수 있으므로 반복 될 수 있음).

CountDownLatch 동작을 시뮬레이트하려면 invokeAll() 메서드를 사용할 수 있습니다.

  1. 따옴표를 사용하지 않은 한 가지 메커니즘이 ForkJoinPool입니다.

    ForkJoinPool 은 Java 7에서 Java에 추가되었습니다. ForkJoinPool 은 Java ExecutorService 와 비슷하지만 한 가지 차이점이 있습니다. ForkJoinPool 쉽게 작업을 한 다음에 제출 작은 작업으로 작업을 분할 할 수있게 ForkJoinPool 너무. 자유 작업자 스레드가 작업량이 많은 스레드에서 작업을 도용하면 작업 도용이 ForkJoinPool 에서 발생합니다.

    Java 8은 ExecutorService 에 하나의 API를 추가하여 작업 도용 풀을 작성합니다. RecursiveTaskRecursiveAction 을 만들지 않아도 ForkJoinPool 을 사용할 수 있습니다.

    public static ExecutorService newWorkStealingPool()
    

    사용 가능한 모든 프로세서를 대상 병렬 처리 수준으로 사용하여 작업 도용 스레드 풀을 만듭니다.

    기본적으로 매개 변수로 CPU 코어 수를 사용합니다.

이 4 가지 메커니즘은 모두 서로 보완 적입니다. 제어하려는 세분화 수준에 따라 올바른 것을 선택해야합니다.

ExecutorService의 모든 작업이 완료 될 때까지 기다립니다.

Executor에 제출 된 작업의 완료를 기다리는 다양한 옵션을 살펴 보겠습니다.

  1. ExecutorService invokeAll()

    지정된 태스크를 실행 해, 모든 것이 완료했을 때 상태 및 결과를 보관 유지하는 Future의리스트를 돌려줍니다.

예:

import java.util.concurrent.*;
import java.util.*;

public class InvokeAllDemo{
    public InvokeAllDemo(){
        System.out.println("creating service");
        ExecutorService service = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
        
        List<MyCallable> futureList = new ArrayList<MyCallable>();
        for (int i = 0; i < 10; i++){
            MyCallable myCallable = new MyCallable((long)i);
            futureList.add(myCallable);
        }
        System.out.println("Start");
        try{
            List<Future<Long>> futures = service.invokeAll(futureList);  
        } catch(Exception err){
            err.printStackTrace();
        }
        System.out.println("Completed");
        service.shutdown();
    }
    public static void main(String args[]){
        InvokeAllDemo demo = new InvokeAllDemo();
    }
    class MyCallable implements Callable<Long>{
        Long id = 0L;
        public MyCallable(Long val){
            this.id = val;
        }
        public Long call(){
            // Add your business logic
            return id;
        }
    }
}
  1. CountDownLatch

    하나 이상의 스레드가 다른 스레드에서 수행되는 일련의 작업이 완료 될 때까지 대기하도록하는 동기화 보조 도구입니다.

    CountDownLatch 는 주어진 카운트로 초기화됩니다. await 메서드는 countDown() 메서드 호출로 인해 현재 카운트가 0이 될 때까지 블록합니다. 그 후에는 대기중인 모든 스레드가 해제되고 모든 후속 호출 대기가 즉시 반환됩니다. 이것은 일회성 현상입니다. 카운트를 재설정 할 수 없습니다. 개수를 다시 설정하는 버전이 필요한 경우 CyclicBarrier 사용을 고려하십시오.

  2. Executors의 ForkJoinPool 또는 newWorkStealingPool()

  3. ExecutorService 제출 한 후에 생성 된 모든 Future 객체를 반복합니다.

  4. ExecutorService의 오라클 설명서 페이지에서 권장되는 종료 방법 :

    void shutdownAndAwaitTermination(ExecutorService pool) {
        pool.shutdown(); // Disable new tasks from being submitted
        try {
          // Wait a while for existing tasks to terminate
          if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {
            pool.shutdownNow(); // Cancel currently executing tasks
            // Wait a while for tasks to respond to being cancelled
            if (!pool.awaitTermination(60, TimeUnit.SECONDS))
                System.err.println("Pool did not terminate");
          }
        } catch (InterruptedException ie) {
          // (Re-)Cancel if current thread also interrupted
          pool.shutdownNow();
          // Preserve interrupt status
          Thread.currentThread().interrupt();
        }
    

    shutdown(): 이전에 제출 된 작업이 실행되는 순서대로 종료를 시작하지만 새 작업은 수락되지 않습니다.

    shutdownNow(): 적극적으로 실행중인 모든 작업을 중지하고 대기중인 작업 처리를 중단하고 실행 대기중인 작업 목록을 반환합니다.

    위의 예에서 작업을 완료하는 데 더 많은 시간이 걸리면 조건을 while 조건으로 변경할 수 있습니다

    바꾸다

    if (!pool.awaitTermination(60, TimeUnit.SECONDS))
    

    while(!pool.awaitTermination(60, TimeUnit.SECONDS)) {
      Thread.sleep(60000);
    

    }

다양한 유형의 ExecutorService에 대한 사용 사례

Executors 는 특정 필요를 충족시키는 다른 유형의 ThreadPool을 반환합니다.

  1. public static ExecutorService newSingleThreadExecutor()

    무제한 큐를 조작하고있는 단일의 워커 thread를 사용하는 Executor를 작성합니다.

    newFixedThreadPool(1)newSingleThreadExecutor() 사이에는 java 의사가 후자에 대해 말한 것처럼 차이가 있습니다.

    달리 등가 인 newFixedThreadPool (1)과 달리, 돌려 주어지는 executor는, 추가 thread를 사용하도록 (듯이) 재구성 가능하지 않는 것이 보증되고 있습니다.

    즉, newFixedThreadPool 은 나중에 프로그램에서 다음과 같이 재구성 할 수 있습니다. ((ThreadPoolExecutor) fixedThreadPool).setMaximumPoolSize(10) newSingleThreadExecutor 에는 사용할 수 없습니다.

    사용 사례:

    1. 제출 된 작업을 순서대로 실행하려고합니다.
    2. 모든 요청을 처리하기 위해 하나의 스레드 만 필요합니다.

    단점 :

    1. 제한이없는 큐가 위험합니다.
  2. public static ExecutorService newFixedThreadPool(int nThreads)

    공유 안 바운드 큐에서 작동하는 고정 된 수의 스레드를 다시 사용하는 스레드 풀을 만듭니다. 언제든지 nThreads 스레드가 활성 처리 작업이됩니다. 모든 스레드가 활성 상태 일 때 추가 작업이 제출되면 스레드가 사용 가능할 때까지 대기열에서 대기합니다.

    사용 사례:

    1. 사용 가능한 코어의 효과적인 사용. nThreadsRuntime.getRuntime().availableProcessors()
    2. 스레드 수가 스레드 풀의 수를 초과해서는 안되는 경우

    단점 :

    1. 제한되지 않은 큐는 유해합니다.
  3. public static ExecutorService newCachedThreadPool()

    필요에 따라서 새로운 thread를 작성하는 thread 풀을 작성 합니다만, 이용 가능한 경우는 이전에 구축 된 thread를 재사용합니다

    사용 사례:

    1. 수명이 짧은 비동기 작업

    단점 :

    1. 제한되지 않은 큐는 유해합니다.
    2. 모든 새로운 스레드는 모든 기존 스레드가 사용중인 경우 새 스레드를 작성합니다. 작업의 지속 시간이 길어지면 더 많은 수의 스레드가 생성되어 시스템의 성능이 저하됩니다. 이 경우 대안 : newFixedThreadPool
  1. public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)

    지정된 지연 후에 실행하거나 주기적으로 실행하도록 명령을 예약 할 수있는 스레드 풀을 만듭니다.

    사용 사례:

    1. 지연이있는 반복 이벤트 처리 (특정 시간 간격으로 앞으로 발생 함)

    단점 :

    1. 제한되지 않은 큐는 유해합니다.

    5. public static ExecutorService newWorkStealingPool()

    사용 가능한 모든 프로세서를 대상 병렬 처리 수준으로 사용하여 작업 도용 스레드 풀을 만듭니다.

    사용 사례:

    1. 분단하고 정복하는 유형의 문제.
    2. 유휴 스레드의 효과적인 사용. 유휴 스레드는 작업량이 많은 스레드에서 작업을 훔칩니다.

    단점 :

    1. 제한되지 않은 큐 크기는 유해합니다.

이러한 모든 ExecutorService에서 하나의 공통적 인 단점, 즉 제한되지 않은 대기열을 볼 수 있습니다. 이것은 ThreadPoolExecutor 로 처리됩니다.

ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, 
TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory,
RejectedExecutionHandler handler)

ThreadPoolExecutor 를 사용하면

  1. 스레드 풀 크기를 동적으로 제어
  2. BlockingQueue 의 용량 설정
  3. 대기열이 가득 차면 RejectionExecutionHander 정의하십시오.
  4. Thread 생성 중에 추가 기능을 추가하는 CustomThreadFactory (public Thread newThread(Runnable r)

스레드 풀 사용

스레드 풀은 주로 ExecutorService 에서 메서드를 호출하는 데 사용됩니다.

다음 메소드를 사용하여 실행 작업을 제출할 수 있습니다.

방법 기술
submit 제출 된 저작물을 실행하고 결과를 얻는 데 사용할 수있는 미래를 반환합니다.
execute 반환 값을 얻지 않고 미래의 언젠가 작업을 실행하십시오.
invokeAll 작업 목록을 실행하고 선물 목록을 반환합니다.
invokeAny 모든 것을 실행하지만 성공한 결과 만 반환합니다 (예외없이).

스레드 풀을 끝내면 shutdown() 을 호출하여 스레드 풀을 shutdown() 할 수 있습니다. 보류중인 모든 작업이 실행됩니다. 모든 작업이 실행될 때까지 기다리려면 awaitTermination 또는 isShutdown() 반복 할 수 있습니다.



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow