[java] ThreadPoolExecutor의 코어 풀 크기 대 최대 풀 크기

우리가 이야기 할 때 코어 풀 크기최대 풀 크기 의 차이점은 정확히 무엇입니까 ThreadPoolExecutor?
예를 들어 설명 할 수 있습니까?



답변

에서 이 블로그 게시물 :

이 예를 들어 보자. 시작 스레드 풀 크기는 1, 코어 풀 크기는 5, 최대 풀 크기는 10, 대기열은 100입니다.

요청이 들어 오면 스레드는 최대 5 개까지 생성되고 작업은 100 개에 도달 할 때까지 대기열에 추가됩니다. 대기열이 가득 차면 최대 maxPoolSize. 모든 스레드가 사용 중이고 대기열이 가득 차면 작업이 거부됩니다. 대기열이 줄어들면 활성 스레드 수도 감소합니다.


답변

IF 실행 스레드> corePoolSize를 & <maxPoolSize 총 작업 대기열이 가득하고 새로운 하나가 도착하면, 새로운 스레드를 생성합니다.

Form doc : ( corePoolSize 이상 이지만 maximumPoolSize 미만의 스레드가 실행중인 경우 대기열이 가득 찬 경우에만 새 스레드가 생성됩니다.)

이제 간단한 예를 들어 보겠습니다.

ThreadPoolExecutor executorPool = new ThreadPoolExecutor(5, 10, 3, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(50));

여기서 5는 corePoolSize입니다 . 즉, Jvm이 처음 5 개 작업에 대한 새 작업에 대한 새 스레드를 생성합니다. 다른 작업은 대기열이 가득 찰 때까지 대기열에 추가됩니다 (작업 50 개).

10은 maxPoolSize입니다 . JVM은 최대 10 개의 스레드를 만들 수 있습니다. 이미 5 개의 작업 / 스레드가 실행 중이고 대기열이 50 개의 보류 작업으로 가득 차 있고 하나 이상의 새 요청 / 작업이 대기열에 도착하면 JVM은 최대 10 개의 새 스레드를 생성합니다 (총 스레드 = 이전 5 개 + 새 5 개). ;

new ArrayBlockingQueue (50) = 전체 대기열 크기-50 개의 작업을 대기열에 넣을 수 있습니다.

10 개의 스레드가 모두 실행되고 새 작업이 도착하면 새 작업이 거부됩니다.

SUN에서 내부적으로 스레드를 생성하는 규칙 :

  1. 스레드 수가 corePoolSize보다 적 으면 새 스레드를 만들어 새 작업을 실행합니다.

  2. 스레드 수가 corePoolSize와 같거나 크면 작업을 대기열에 넣습니다.

  3. 대기열이 가득 차고 스레드 수가 maxPoolSize보다 적 으면 작업을 실행할 새 스레드를 만듭니다.

  4. 대기열이 가득 차고 스레드 수가 maxPoolSize보다 크거나 같으면 작업을 거부합니다.

희망, 이것은 HelpFul .. 그리고 내가 틀렸다면 나를 고쳐주세요 …


답변

에서 의 DoC :

새 작업이 execute (java.lang.Runnable) 메소드에 제출되고 corePoolSize 스레드보다 적은 수의 스레드가 실행 중이면 다른 작업자 스레드가 유휴 상태 인 경우에도 요청을 처리하기 위해 새 스레드가 생성됩니다. corePoolSize보다 많지만 maximumPoolSize보다 작은 스레드가 실행중인 경우 대기열이 가득 찬 경우에만 새 스레드가 생성됩니다.

더욱이:

corePoolSize 및 maximumPoolSize를 동일하게 설정하여 고정 크기 스레드 풀을 만듭니다. maximumPoolSize를 Integer.MAX_VALUE와 같이 본질적으로 제한되지 않은 값으로 설정하면 풀이 임의의 수의 동시 작업을 수용 할 수 있습니다. 대부분의 경우 코어 및 최대 풀 크기는 생성시에만 설정되지만 setCorePoolSize (int) 및 setMaximumPoolSize (int)를 사용하여 동적으로 변경할 수도 있습니다.


답변

팩토리 클래스 ThreadPoolExecutor를 사용하는 대신 수동으로 생성하기로 결정한 경우 Executors생성자 중 하나를 사용하여 생성하고 구성해야합니다. 이 클래스의 가장 광범위한 생성자는 다음과 같습니다.

public ThreadPoolExecutor(
    int corePoolSize,
    int maxPoolSize,
    long keepAlive,
    TimeUnit unit,
    BlockingQueue<Runnable> workQueue,
    RejectedExecutionHandler handler
);

보시다시피 다음을 구성 할 수 있습니다.

  • 코어 풀 크기 (스레드 풀이 유지하려고 시도하는 크기).
  • 최대 풀 크기.
  • 유휴 스레드가 해체 될 수있는 시간 인 연결 유지 시간입니다.
  • 실행을 기다리는 작업을 보관하는 작업 대기열입니다.
  • 작업 제출이 거부 될 때 적용 할 정책입니다.

대기중인 작업 수 제한

실행중인 동시 작업 수를 제한하고 스레드 풀 크기를 조정하는 것은 예측 가능성 및 안정성 측면에서 애플리케이션 및 실행 환경에 큰 이점을 나타냅니다. 제한없는 스레드 생성은 결국 런타임 리소스를 고갈시키고 결과적으로 애플리케이션이 경험할 수 있습니다. , 응용 프로그램을 불안정하게 만들 수도있는 심각한 성능 문제.

이는 문제의 한 부분에 대한 해결책입니다. 실행중인 작업의 수를 제한하고 있지만 나중에 실행하기 위해 제출하고 대기열에 넣을 수있는 작업의 수를 제한하지 않습니다. 응용 프로그램은 나중에 리소스 부족을 경험하지만 제출 속도가 지속적으로 실행 속도를 초과하면 결국이를 경험하게됩니다.

이 문제에 대한 해결책은 다음과 같습니다. 대기중인 작업을 유지하기 위해 실행기에 차단 대기열을 제공합니다. 대기열이 꽉 찬 경우 제출 된 작업은 “거부”됩니다. 는 RejectedExecutionHandler작업 제출이 거부 될 때 호출되며, 거부 동사가 이전 항목에서 인용 한 이유의 그. 자체 거부 정책을 구현하거나 프레임 워크에서 제공하는 기본 제공 정책 중 하나를 사용할 수 있습니다.

기본 거부 정책에는 실행자가 RejectedExecutionException. 그러나 다른 기본 제공 정책을 통해 다음을 수행 할 수 있습니다.

  • 작업을 조용히 버립니다.
  • 가장 오래된 작업을 버리고 마지막 작업을 다시 제출하십시오.
  • 호출자의 스레드에서 거부 된 작업을 실행합니다.


답변

출처

ThreadPoolExecutor 풀 크기 규칙

ThreadPoolExecutor's풀 의 크기에 대한 규칙 은 일반적으로 잘못 이해되어 있습니다. 왜냐하면 풀이 필요하다고 생각하는 방식이나 원하는 방식으로 작동하지 않기 때문입니다.

이 예를 들어 보자. 시작 스레드 풀 크기는 1, 코어 풀 크기는 5, 최대 풀 크기는 10, 대기열은 100입니다.

썬의 방식 : 요청이 들어 오면 스레드가 최대 5 개까지 생성 된 다음 작업이 100 개에 도달 할 때까지 대기열에 추가됩니다. 대기열이 가득 차면 최대 새 스레드가 생성됩니다. maxPoolSize . 모든 스레드가 사용 중이고 대기열이 가득 차면 작업이 거부됩니다. 큐가 줄어들면 활성 스레드 수가 줄어 듭니다.

사용자 예상 방식 : 요청이 들어 오면 스레드가 최대 10 개까지 생성 된 다음 작업이 100 개에 도달 할 때까지 대기열에 추가되고 거부되는 시점입니다. 스레드 수는 대기열이 비워 질 때까지 최대로 이름이 바뀝니다. 대기열이 비어 있으면 스레드가 corePoolSize남아 있을 때까지 죽습니다 .

차이점은 사용자가 더 일찍 풀 크기를 늘리기 시작하고 대기열을 더 작게 만들고 싶어한다는 것입니다. Sun 방법은 풀 크기를 작게 유지하고로드가 많아지면 늘려야합니다.

다음은 스레드 생성에 대한 Sun의 규칙입니다.

  1. 스레드 수가보다 적 으면 corePoolSize새 스레드를 만들어 새 작업을 실행합니다.
  2. 스레드 수가과 같거나 크면 corePoolSize작업을 대기열에 넣습니다.
  3. 대기열이 가득 차고 스레드 수가보다 적은 경우 maxPoolSize작업을 실행할 새 스레드를 만듭니다.
  4. 대기열이 가득 차고 스레드 수가 이상 maxPoolSize이면 작업을 거부합니다. 길고 짧은 것은 대기열이 가득 찼을 때만 새 스레드가 생성되므로 제한되지 않은 대기열을 사용하는 경우 스레드 수가을 초과하지 않는다는 것 corePoolSize입니다.

더 자세한 설명은 말의 입에서 가져옵니다 : ThreadPoolExecutorAPI 문서.

ThreadPoolExecutor코드 예제와 함께 작동 하는 방법을 설명하는 정말 좋은 포럼 게시물이 있습니다 . http://forums.sun.com/thread.jspa?threadID=5401400&tstart=0

추가 정보 : http://forums.sun.com/thread.jspa?threadID=5224557&tstart=450


답변

javadoc에서 corepoolsize 및 maxpoolsize 용어의 정의를 찾을 수 있습니다. http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ThreadPoolExecutor.html

위의 링크에 귀하의 질문에 대한 답변이 있습니다. 그러나 명확하게하기 위해서입니다. 응용 프로그램은 corePoolSize에 도달 할 때까지 스레드를 계속 생성합니다. 여기서 생각은 이러한 많은 스레드가 작업 유입을 처리하기에 충분해야한다는 것입니다. corePoolSize 스레드가 생성 된 후 새 작업이 발생하면 작업이 대기열에 추가됩니다. 큐가 가득 차면 실행기는 새 스레드를 만들기 시작합니다. 일종의 균형입니다. 본질적으로 의미하는 것은 작업의 유입이 처리 능력 이상이라는 것입니다. 따라서 Executor는 최대 스레드 수에 도달 할 때까지 새 스레드를 다시 만들기 시작합니다. 다시 말하지만, 대기열이 가득 찬 경우에만 새 스레드가 생성됩니다.


답변

블로그의 좋은 설명 :

삽화

public class ThreadPoolExecutorExample {

    public static void main (String[] args) {
        createAndRunPoolForQueue(new ArrayBlockingQueue<Runnable>(3), "Bounded");
        createAndRunPoolForQueue(new LinkedBlockingDeque<>(), "Unbounded");
        createAndRunPoolForQueue(new SynchronousQueue<Runnable>(), "Direct hand-off");
    }

    private static void createAndRunPoolForQueue (BlockingQueue<Runnable> queue,
                                                                      String msg) {
        System.out.println("---- " + msg + " queue instance = " +
                                                  queue.getClass()+ " -------------");

        ThreadPoolExecutor e = new ThreadPoolExecutor(2, 5, Long.MAX_VALUE,
                                 TimeUnit.NANOSECONDS, queue);

        for (int i = 0; i < 10; i++) {
            try {
                e.execute(new Task());
            } catch (RejectedExecutionException ex) {
                System.out.println("Task rejected = " + (i + 1));
            }
            printStatus(i + 1, e);
        }

        e.shutdownNow();

        System.out.println("--------------------\n");
    }

    private static void printStatus (int taskSubmitted, ThreadPoolExecutor e) {
        StringBuilder s = new StringBuilder();
        s.append("poolSize = ")
         .append(e.getPoolSize())
         .append(", corePoolSize = ")
         .append(e.getCorePoolSize())
         .append(", queueSize = ")
         .append(e.getQueue()
                  .size())
         .append(", queueRemainingCapacity = ")
         .append(e.getQueue()
                  .remainingCapacity())
         .append(", maximumPoolSize = ")
         .append(e.getMaximumPoolSize())
         .append(", totalTasksSubmitted = ")
         .append(taskSubmitted);

        System.out.println(s.toString());
    }

    private static class Task implements Runnable {

        @Override
        public void run () {
            while (true) {
                try {
                    Thread.sleep(1000000);
                } catch (InterruptedException e) {
                    break;
                }
            }
        }
    }
}

출력 :

---- Bounded queue instance = class java.util.concurrent.ArrayBlockingQueue -------------
poolSize = 1, corePoolSize = 2, queueSize = 0, queueRemainingCapacity = 3, maximumPoolSize = 5, totalTasksSubmitted = 1
poolSize = 2, corePoolSize = 2, queueSize = 0, queueRemainingCapacity = 3, maximumPoolSize = 5, totalTasksSubmitted = 2
poolSize = 2, corePoolSize = 2, queueSize = 1, queueRemainingCapacity = 2, maximumPoolSize = 5, totalTasksSubmitted = 3
poolSize = 2, corePoolSize = 2, queueSize = 2, queueCapacity = 1, maximumPoolSize = 5, totalTasksSubmitted = 4
poolSize = 2, corePoolSize = 2, queueSize = 3, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 5
poolSize = 3, corePoolSize = 2, queueSize = 3, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 6
poolSize = 4, corePoolSize = 2, queueSize = 3, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 7
poolSize = 5, corePoolSize = 2, queueSize = 3, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 8
Task rejected = 9
poolSize = 5, corePoolSize = 2, queueSize = 3, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 9
Task rejected = 10
poolSize = 5, corePoolSize = 2, queueSize = 3, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 10
--------------------

---- Unbounded queue instance = class java.util.concurrent.LinkedBlockingDeque -------------
poolSize = 1, corePoolSize = 2, queueSize = 0, queueRemainingCapacity = 2147483647, maximumPoolSize = 5, totalTasksSubmitted = 1
poolSize = 2, corePoolSize = 2, queueSize = 0, queueRemainingCapacity = 2147483647, maximumPoolSize = 5, totalTasksSubmitted = 2
poolSize = 2, corePoolSize = 2, queueSize = 1, queueRemainingCapacity = 2147483646, maximumPoolSize = 5, totalTasksSubmitted = 3
poolSize = 2, corePoolSize = 2, queueSize = 2, queueRemainingCapacity = 2147483645, maximumPoolSize = 5, totalTasksSubmitted = 4
poolSize = 2, corePoolSize = 2, queueSize = 3, queueRemainingCapacity = 2147483644, maximumPoolSize = 5, totalTasksSubmitted = 5
poolSize = 2, corePoolSize = 2, queueSize = 4, queueRemainingCapacity = 2147483643, maximumPoolSize = 5, totalTasksSubmitted = 6
poolSize = 2, corePoolSize = 2, queueSize = 5, queueRemainingCapacity = 2147483642, maximumPoolSize = 5, totalTasksSubmitted = 7
poolSize = 2, corePoolSize = 2, queueSize = 6, queueRemainingCapacity = 2147483641, maximumPoolSize = 5, totalTasksSubmitted = 8
poolSize = 2, corePoolSize = 2, queueSize = 7, queueRemainingCapacity = 2147483640, maximumPoolSize = 5, totalTasksSubmitted = 9
poolSize = 2, corePoolSize = 2, queueSize = 8, queueRemainingCapacity = 2147483639, maximumPoolSize = 5, totalTasksSubmitted = 10
--------------------

---- Direct hand-off queue instance = class java.util.concurrent.SynchronousQueue -------------
poolSize = 1, corePoolSize = 2, queueSize = 0, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 1
poolSize = 2, corePoolSize = 2, queueSize = 0, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 2
poolSize = 3, corePoolSize = 2, queueSize = 0, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 3
poolSize = 4, corePoolSize = 2, queueSize = 0, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 4
poolSize = 5, corePoolSize = 2, queueSize = 0, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 5
Task rejected = 6
poolSize = 5, corePoolSize = 2, queueSize = 0, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 6
Task rejected = 7
poolSize = 5, corePoolSize = 2, queueSize = 0, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 7
Task rejected = 8
poolSize = 5, corePoolSize = 2, queueSize = 0, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 8
Task rejected = 9
poolSize = 5, corePoolSize = 2, queueSize = 0, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 9
Task rejected = 10
poolSize = 5, corePoolSize = 2, queueSize = 0, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 10
--------------------


Process finished with exit code 0