当我们谈论时,核心池大小和最大池大小之间到底有什么区别ThreadPoolExecutor
?
可以借助示例进行解释吗?
当我们谈论时,核心池大小和最大池大小之间到底有什么区别ThreadPoolExecutor
?
可以借助示例进行解释吗?
Answers:
从这篇博客文章:
举这个例子。起始线程池大小为1,核心池大小为5,最大池大小为10,队列为100。
随着请求的到来,将最多创建5个线程,然后将任务添加到队列中,直到达到100个。当队列已满时,将最多创建线程
maxPoolSize
。一旦所有线程都被使用并且队列已满,任务将被拒绝。随着队列的减少,活动线程的数量也会减少。
allowCoreThreadTimeOut(boolean)
,允许在给定的空闲时间后杀死核心线程。将其设置为true并设置core threads
= max threads
允许线程池在0到之间缩放max threads
。
如果正在运行的线程> corePoolSize&<maxPoolSize,则如果Total任务队列已满并且有新线程到达,则创建一个新Thread。
表单文档:(如果正在运行的线程数超过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内部创建线程的规则:
如果线程数小于corePoolSize,则创建一个新线程以运行新任务。
如果线程数等于(或大于)corePoolSize,则将任务放入队列。
如果队列已满,并且线程数小于maxPoolSize,请创建一个新线程来运行任务。
如果队列已满,并且线程数大于或等于maxPoolSize,则拒绝该任务。
希望这是HelpFul ..如果我错了,请纠正我...
从文档:
当在方法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。
Sun的方式:随着请求的到来,最多将创建5个线程,然后将任务添加到队列中,直到达到100个。当队列已满时,将最多创建一个新线程maxPoolSize
。一旦所有线程都被使用并且队列已满,任务将被拒绝。随着队列的减少,活动线程的数量也会减少。
用户预期的方式:随着请求的进入,最多将创建10个线程,然后将任务添加到队列中,直到达到100个为止,此时它们被拒绝。线程数将最大重命名,直到队列为空。当队列为空时,线程将死掉直到corePoolSize
剩下。
不同之处在于,用户希望更早地开始增加池的大小,并希望队列变小,而Sun方法则希望保持池的大小小,并且只有在负载变得很大时才增加池的大小。
简单来说,这是Sun的线程创建规则:
corePoolSize
,则创建一个新线程以运行新任务。corePoolSize
,则将任务放入队列。maxPoolSize
,请创建一个新线程来运行任务。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
您可以在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
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);
}
了解ThreadPoolExecutor
提交新任务时的内部行为有助于我了解如何corePoolSize
以及maximumPoolSize
不同之处。
让:
N
是池中的线程数,getPoolSize()
。活动线程+空闲线程。T
提交给执行者/池的任务数量。C
是核心池的大小getCorePoolSize()
。在新任务进入队列之前,每个池最多可以为传入任务创建多少个线程。M
是最大池大小,getMaximumPoolSize()
。池可以分配的最大线程数。ThreadPoolExecutor
提交新任务时Java中的行为:
N <= C
,没有为空闲线程分配新的传入任务,而是创建了一个新线程。N > C
并且,如果有空闲线程,则在那里分配新任务。N > C
如果没有空闲的线程,新任务放入队列。此处未创建新的线程。M
。如果M
达成,我们将拒绝任务。重要的是不要在队列已满之前不要创建新线程!资料来源:
corePoolSize = 0
和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.
corePoolSize = 10
和maximumPoolSize = 10
与队列容量50
。这将导致池中有10个活动线程。当队列中有50个项目时,任务将被拒绝。
execute(task #1)
before task #1 submitted to executor: java.util.concurrent.ThreadPoolExecutor@32d9e072[Running, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 0]
after task #1 submitted to executor: java.util.concurrent.ThreadPoolExecutor@32d9e072[Running, pool size = 1, active threads = 1, queued tasks = 0, completed tasks = 0]
execute(task #2)
before task #2 submitted to executor: java.util.concurrent.ThreadPoolExecutor@32d9e072[Running, pool size = 1, active threads = 1, queued tasks = 0, completed tasks = 0]
after task #2 submitted to executor: java.util.concurrent.ThreadPoolExecutor@32d9e072[Running, pool size = 2, active threads = 2, queued tasks = 0, completed tasks = 0]
execute(task #3)
before task #3 submitted to executor: java.util.concurrent.ThreadPoolExecutor@32d9e072[Running, pool size = 2, active threads = 2, queued tasks = 0, completed tasks = 0]
after task #3 submitted to executor: java.util.concurrent.ThreadPoolExecutor@32d9e072[Running, pool size = 3, active threads = 3, queued tasks = 0, completed tasks = 0]
... executed a few tasks...
execute(task #11)
before task #11 submitted to executor: java.util.concurrent.ThreadPoolExecutor@32d9e072[Running, pool size = 10, active threads = 10, queued tasks = 0, completed tasks = 0]
after task #11 submitted to executor: java.util.concurrent.ThreadPoolExecutor@32d9e072[Running, pool size = 10, active threads = 10, queued tasks = 1, completed tasks = 0]
... executed a few tasks...
execute(task #51)
before task #51 submitted to executor: java.util.concurrent.ThreadPoolExecutor@32d9e072[Running, pool size = 10, active threads = 10, queued tasks = 50, completed tasks = 0]
Task was rejected as we have reached `maximumPoolSize`.