我在使用 Java 6 的 ThreadPoolExecutor 时遇到了一个奇怪的问题。有时当我动态更改 corePoolSize 时,我观察到线程池没有处理应有的任务。
例如,如果我有 4 个作为 corePoolSize 并且有很多任务在队列中等待,则执行程序最多处理 3 个,有时甚至是 2 个。
在调查问题时,我注意到当我增加或减少 corePoolSize 时,我从未更改过 maxPoolSize。从我的申请开始,它一直是 1。
从未在 Java 文档中找到提及 maxPoolSize 小于核心的影响的声明。
然后,当我检查源代码时,我注意到在 costructor 和 setCorePoolSize 方法中,都会检查 maxPoolSize 小于 corePoolSize 的位置,如果抛出了非法ArgumentException。查看下面的代码。
构造函数
public ThreadPoolExecutor(
int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler
) {
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
设置最大池大小
public void setMaximumPoolSize(int maximumPoolSize) {
if (maximumPoolSize <= 0 || maximumPoolSize < corePoolSize)
throw new IllegalArgumentException();
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
int extra = this.maximumPoolSize - maximumPoolSize;
this.maximumPoolSize = maximumPoolSize;
if (extra > 0 && poolSize > maximumPoolSize) {
try {
Iterator<Worker> it = workers.iterator();
while (it.hasNext() &&
extra > 0 &&
poolSize > maximumPoolSize) {
it.next().interruptIfIdle();
--extra;
}
} catch (SecurityException ignore) {
// Not an error; it is OK if the threads stay live
}
}
} finally {
mainLock.unlock();
}
}
所以,显然这是一个不受欢迎的情况。但是在 setCorePoolSize 中没有检查,导致 maximumPoolSize 最终小于 corePoolSize,并且没有记录这种情况的影响。
设置核心池大小
public void setCorePoolSize(int corePoolSize) {
if (corePoolSize < 0)
throw new IllegalArgumentException();
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
int extra = this.corePoolSize - corePoolSize;
this.corePoolSize = corePoolSize;
if (extra < 0) {
int n = workQueue.size(); // don't add more threads than tasks
while (extra++ < 0 && n-- > 0 && poolSize < corePoolSize) {
Thread t = addThread(null);
if (t == null)
break;
}
}
else if (extra > 0 && poolSize > corePoolSize) {
try {
Iterator<Worker> it = workers.iterator();
while (it.hasNext() &&
extra-- > 0 &&
poolSize > corePoolSize &&
workQueue.remainingCapacity() == 0)
it.next().interruptIfIdle();
} catch (SecurityException ignore) {
// Not an error; it is OK if the threads stay live
}
}
} finally {
mainLock.unlock();
}
}
你不认为应该有一种机制来防止这种情况结束吗?