核心池大小与ThreadPoolExecutor中的最大池大小

时间:2013-07-15 16:50:00

标签: threadpoolexecutor

当我们谈论ThreadPoolExecutor时,核心池大小和最大池大小之间究竟有什么区别?可以借助一个例子来解释吗?

11 个答案:

答案 0 :(得分:90)

来自this blog post

  

举个例子。起始线程池大小为1,核心池大小为   5,最大池大小为10,队列为100.

     

当请求进来时,   最多将创建5个线程,然后将任务添加到   队列直到达到100.当队列满了新线程时   创建至maxPoolSize。一旦所有线程都在使用中   队列是完整的任务将被拒绝。随着队列的减少,同样如此   活动线程数。

答案 1 :(得分:20)

如果正在运行的主题> corePoolSize& < maxPoolSize ,然后在Total任务队列已满并且新任务队列到达时创建一个新线程。

表格文件: (如果有超过 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,则拒绝该任务。

  5. 希望,这是HelpFul ..如果我错了,请纠正我......

答案 2 :(得分:17)

来自the doc

  

在方法execute(java.lang.Runnable)中提交新任务时,   并且运行的corePoolSize线程少于一个新线程   创建用于处理请求,即使其他工作线程处于空闲状态。   如果有多个corePoolSize但小于maximumPoolSize   如果线程正在运行,则只有在队列出现时才会创建新线程   充分。

此外:

  

通过设置corePoolSize和maximumPoolSize相同,您可以创建   固定大小的线程池。通过将maximumPoolSize设置为一个基本上   无限制的值,如Integer.MAX_VALUE,您允许池到   容纳任意数量的并发任务。最典型的是,   核心和最大池大小仅在构造时设置,但它们   也可以使用setCorePoolSize(int)和动态更改   setMaximumPoolSize(INT)。

答案 3 :(得分:5)

如果您决定手动创建ThreadPoolExecutor而不是使用Executors工厂类,则需要使用其中一个构造函数创建和配置一个工厂类。这个类中最广泛的构造函数是:

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

如您所见,您可以配置:

  • 核心池大小(线程池将尝试坚持的大小)。
  • 最大池大小。
  • 保持活动时间,此时空闲线程有资格被拆除。
  • 用于保存等待执行的任务的工作队列。
  • 拒绝任务提交时应用的政策。

限制排队任务数

限制正在执行的并发任务的数量,调整线程池的大小,在可预测性和稳定性方面为您的应用程序及其执行环境带来巨大好处:无限制的线程创建最终将耗尽运行时资源并且您的应用程序可能会遇到因此,严重的性能问题甚至可能导致应用程序不稳定。

这只是问题的一部分的解决方案:您正在限制正在执行的任务数量但不限制可以提交和排队以便以后执行的作业数量。该应用程序将在以后遇到资源短缺,但如果提交率始终超过执行率,它将最终体验到它。

此问题的解决方案是: 为执行程序提供阻塞队列以保存等待任务。在队列填满的情况下,提交的任务将被拒绝&#34;。 在拒绝任务提交时调用RejectedExecutionHandler,这就是在前一项中引用被拒绝的动词的原因。您可以实施自己的拒绝策略或使用框架提供的内置策略之一。

默认拒绝政策让执行者抛出RejectedExecutionException。但是,其他内置策略可以让您:

  • 默默地丢弃工作。
  • 丢弃最旧的作业并尝试重新提交最后一份作业。
  • 在来电者的主题上执行被拒绝的任务。

答案 4 :(得分:4)

Source

ThreadPoolExecutor池大小的规则

ThreadPoolExecutor's池大小的规则通常会被误解,因为它无法按照您认为的方式或您想要的方式发挥作用。

以这个例子为例。起始线程池大小为1,核心池大小为5,最大池大小为10,队列为100。

Sun的方式:随着请求的进入,最多将创建5个线程,然后将任务添加到队列,直到达到100个。当队列已满时,将创建多达maxPoolSize个新线程。一旦所有线程都被使用并且队列已满,任务将被拒绝。随着队列的减少,活动线程数也会减少。

用户预期的方式:随着请求的进入,最多将创建10个线程,然后将任务添加到队列中,直到达到100个为止,此时它们被拒绝。线程数将最大重命名,直到队列为空。当队列为空时,线程将消失,直到剩下corePoolSize

不同之处在于,用户希望更早开始增加池大小,并希望队列变小,这是因为Sun方法要保持池大小小,并且只有在负载变得很大时才增加池大小。

>

以下是Sun创建线程的简单规则:

  1. 如果线程数少于corePoolSize,请创建一个新线程以运行新任务。
  2. 如果线程数等于(或大于)corePoolSize,则将任务放入队列。
  3. 如果队列已满,并且线程数少于maxPoolSize,请创建一个新线程以在其中运行任务。
  4. 如果队列已满,并且线程数大于或等于maxPoolSize,请拒绝任务。 总而言之,就是只有在队列填满时才创建新线程,因此,如果您使用的是无限制队列,那么线程数将不会超过corePoolSize

要获得更全面的解释,请直接从ThreadPoolExecutor API文档中获得。

有一篇非常不错的论坛帖子,向您介绍了ThreadPoolExecutor与代码示例的使用方式:http://forums.sun.com/thread.jspa?threadID=5401400&tstart=0

更多信息:http://forums.sun.com/thread.jspa?threadID=5224557&tstart=450

答案 5 :(得分:3)

您可以在javadoc中找到术语corepoolsize和maxpoolsize的定义。 http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ThreadPoolExecutor.html

上面的链接可以回答您的问题。但是,只是为了说清楚。应用程序将继续创建线程,直到它到达corePoolSize。 我认为这里的想法是这些线程应该足以处理任务的流入。如果在创建corePoolSize线程之后出现新任务,则任务将排队。队列填满后,执行程序将开始创建新线程。这是一种平衡。它本质上意味着任务的流入超过了处理能力。因此,Executor将再次开始创建新线程,直到达到最大线程数。同样,当且仅当队列已满时,才会创建新线程。

答案 6 :(得分:1)

this博客中的好解释

Illustration

import scipy.stats
import numpy as np

r = scipy.stats.pearsonr(x_val, y_val)
fig, ax = matplotlib.pyplot.subplots()
ax.scatter(x_val, y_val, s=75, color='green', edgecolor='black',  linewidth = 2, alpha=0.4)
ax.set_axisbelow(True)
matplotlib.pyplot.axvline(0, c='#262626', linewidth=1.5, alpha=0.9)
matplotlib.pyplot.axhline(0, c='#262626', linewidth=1.5, alpha=0.9)
matplotlib.pyplot.grid(linewidth=1, color='#bfbfbf')
matplotlib.pyplot.xticks(np.arange(-100, 100, 20.0),fontsize=14, fontweight='bold', 
    fontname='Helvetica')
matplotlib.pyplot.yticks(np.arange(-100, 100, 20.0),fontsize=14, fontweight='bold', 
    fontname='Helvetica')
matplotlib.pyplot.text(-95, 85,'Pearson\'s r: %.3f'%r[0], fontsize=14, fontweight='bold', 
    fontname='Helvetica')

matplotlib.pyplot.show()

输出:

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;
                }
            }
        }
    }
}

答案 7 :(得分:1)

摘自 Java一致性要点

CorePoolSize :ThreadPoolExecutor具有一个corePoolSize属性,该属性确定它将启动多少个线程 直到只有在队列已满时才启动新线程

MaximumPoolSize :此属性确定最大启动多少线程。您可以将其设置为Integer。 为了没有上限,请设置MAX_VALUE

答案 8 :(得分:0)

java.util.concurrent.ThreadPoolExecutor

  public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        /*
         * Proceed in 3 steps:
         *
         * 1. If fewer than corePoolSize threads are running, try to
         * start a new thread with the given command as its first
         * task.  The call to addWorker atomically checks runState and
         * workerCount, and so prevents false alarms that would add
         * threads when it shouldn't, by returning false.
         *
         * 2. If a task can be successfully queued, then we still need
         * to double-check whether we should have added a thread
         * (because existing ones died since last checking) or that
         * the pool shut down since entry into this method. So we
         * recheck state and if necessary roll back the enqueuing if
         * stopped, or start a new thread if there are none.
         *
         * 3. If we cannot queue task, then we try to add a new
         * thread.  If it fails, we know we are shut down or saturated
         * and so reject the task.
         */
        int c = ctl.get();
        if (workerCountOf(c) < corePoolSize) {
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        if (isRunning(c) && workQueue.offer(command)) {
            int recheck = ctl.get();
            if (! isRunning(recheck) && remove(command))
                reject(command);
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        else if (!addWorker(command, false))
            reject(command);
    }

答案 9 :(得分:0)

了解提交新任务时ThreadPoolExecutor的内部行为有助于我了解corePoolSizemaximumPoolSize的不同之处。

让:

  • N是池中的线程数getPoolSize()。活动线程+空闲线程。
  • T是提交给执行者/池的任务量。
  • C是核心池大小getCorePoolSize()在新任务进入队列之前,每个池最多可以为传入任务创建多少个线程
  • M是最大池大小getMaximumPoolSize()。池可以分配的最大线程数。

提交新任务时Java中ThreadPoolExecutor的行为:

  • 对于N <= C,没有为空闲线程分配新的传入任务,而是创建了一个新线程。
  • 对于N > C,如果有空闲线程,则在那里分配新任务。
  • 对于N > C,如果没有空闲线程,则将新任务放入队列。 此处未创建新的线程。
  • 队列已满,我们将创建新线程,最高可达M。如果达到M,我们将拒绝任务。重要的是不要在队列满之前才创建新线程!

来源:

示例

队列容量为corePoolSize = 0的{​​{1}}和maximumPoolSize = 10的示例。

这将导致池中只有一个活动线程,直到队列中有50个项目为止。

50

队列容量为executor.execute(task #1): before task #1 submitted to executor: java.util.concurrent.ThreadPoolExecutor@c52dafe[Running, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 0] after task #1 submitted to executor: java.util.concurrent.ThreadPoolExecutor@c52dafe[Running, pool size = 1, active threads = 1, queued tasks = 1, completed tasks = 0] [task #1 immediately queued and kicked in b/c the very first thread is created when `workerCountOf(recheck) == 0`] execute(task #2): before task #2 submitted to executor: java.util.concurrent.ThreadPoolExecutor@c52dafe[Running, pool size = 1, active threads = 1, queued tasks = 0, completed tasks = 0] after task #2 submitted to executor: java.util.concurrent.ThreadPoolExecutor@c52dafe[Running, pool size = 1, active threads = 1, queued tasks = 1, completed tasks = 0] [task #2 not starting before #1 is done] ... executed a few tasks... execute(task #19) before task #19 submitted to executor: java.util.concurrent.ThreadPoolExecutor@735afe38[Running, pool size = 1, active threads = 1, queued tasks = 17, completed tasks = 0] after task #19 submitted to executor: java.util.concurrent.ThreadPoolExecutor@735afe38[Running, pool size = 1, active threads = 1, queued tasks = 18, completed tasks = 0] ... execute(task #51) before task submitted to executor: java.util.concurrent.ThreadPoolExecutor@735afe38[Running, pool size = 1, active threads = 1, queued tasks = 50, completed tasks = 0] after task submitted to executor: java.util.concurrent.ThreadPoolExecutor@735afe38[Running, pool size = 2, active threads = 2, queued tasks = 50, completed tasks = 0] Queue is full. A new thread was created as the queue was full. 的{​​{1}}和corePoolSize = 10的示例。

这将导致池中有10个活动线程。当队列中有50个项目时,任务将被拒绝。

maximumPoolSize = 10

答案 10 :(得分:0)

图中,只考虑正在发生的添加任务

enter image description here