The Executors.newFixedThreadPool
返回一个ExecutorService
;一个不公开的接口(并且probably充分的理由)这样的方法setMaximumPoolSize
and setCorePoolSize
.
如果您创建一个类型池Executors.newFixedThreadPool
,该池应在应用程序的生命周期内保持固定。如果你想要一个可以调整其大小的池,相应地,你应该使用Executors.newCachedThreadPool()
反而。
根据我的理解,Executors.newFixedThreadPool(3) 创建一个池
与 corePoolSize-3 (...)
看看实施情况newFixedThreadPool
可以看出:
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
and
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
所以当你经过时3
to the Executors.newFixedThreadPool
构造函数,你设置both the corePoolSize
和maximumPoolSize
to 3
.
(...) 当我们继续通过池执行任务时,线程将被创建,直到
3 然后当底层队列大小达到100时又新增任务
仍然提交,这就是 maxPoolSize 发挥作用的地方
并且线程现在从 corePoolSize 扩展到 maxPoolSize。
其实这个说法不太准确,不过我稍后会详细解释。现在阅读 Java 文档Executors.newFixedThreadPool
它指出:
创建一个线程池,重用固定数量的线程操作
脱离共享无界队列。在任何时候,最多 nThreads 个线程
将是主动处理任务。如果提交了额外的任务
当所有线程都处于活动状态时,他们将在队列中等待,直到
线程可用。
因此,池不会扩展(除非您明确这样做)。
当上面的程序执行时,我可以看到队列大小达到
黑白 12000-20000,如果是这种情况,则 getPoolSize() 必须打印
值大于 corePoolSize,因为 maxPoolSize 设置为 10,但是
每次它只会打印 3(即 corePoolSize)为什么会这样
发生什么?正如我们期望的那样,它会扩展到 maxPoolSize。
不,这不准确,如果您打印pool.getMaximumPoolSize()
它会返回10
正如预期的那样,调用pool.setMaximumPoolSize(10);
不会改变 corePoolSize 大小。但是,如果你这样做pool.setCorePoolSize(10);
您将增加池以能够处理10
同时线程。
The this.maximumPoolSize
只是定义了池应同时处理的线程数的上限,它不会更改池的当前大小。
为什么池不动态增加其大小?
稍微深入一点newFixedThreadPool
实现中,可以看到Pool初始化了一个任务队列new LinkedBlockingQueue<Runnable>()
大小等于Integer.MAX_VALUE
。看方法execute
人们可以在评论中读到以下内容:
/*
* 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.
*/
如果仔细阅读第2点和第3点,可以推断出only当任务无法添加到队列时,池将创建比 corePoolSize 指定的线程更多的线程。并且自从Executors.newFixedThreadPool
使用队列Integer.MAX_VALUE
您无法看到池动态分配更多资源,除非显式设置corePoolSize
with pool.setCorePoolSize
.
所有这些都是人们不必关心的实现细节。因此,为什么Executors
接口不公开方法,例如setMaximumPoolSize
.
From 线程池执行器 https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ThreadPoolExecutor.html可以阅读的文档:
核心和最大池大小
ThreadPoolExecutor 将自动调整池大小(请参阅
getPoolSize()) 根据 corePoolSize 设置的边界(参见
getCorePoolSize()) 和 MaximumPoolSize(请参阅 getMaximumPoolSize())。
当在方法execute(java.lang.Runnable)中提交新任务时,
并且运行的线程数少于 corePoolSize,则创建一个新线程
创建来处理请求,即使其他工作线程处于空闲状态。如果大于corePoolSize但小于maximumPoolSize
线程正在运行,只有当队列已满时才会创建新线程
满的。通过将 corePoolSize 和 MaximumPoolSize 设置为相同,您可以创建
固定大小的线程池。通过将 MaximumPoolSize 设置为本质上
无界值,例如 Integer.MAX_VALUE,您允许池
容纳任意数量的并发任务。最典型的是,
核心池和最大池大小仅在构建时设置,但它们
也可以使用 setCorePoolSize(int) 动态更改
设置最大池大小(int)。
这基本上证实了为什么池没有动态更新其大小。