Java线程池的核心参数,估计很多人都能信手沾来,但如果再细问几个小问题,估计就有不少人答不上来了。
1. 阻塞队列满了之后,如果线程数上限>核心线程数,新任务提交会导致创建新线程,新线程是优先执行刚到达的新任务还是阻塞队里的第一个任务?
2.超过核心线程数创建的线程,在完成分配的任务之后是立即销毁还是优先检测并执行阻塞队列的未执行任务?
3.为什么超过核心线程数之后,优先安排进入阻塞队列,而不是先检测是否超过最大线程数并创建更多的线程?
我的答案是:
1.刚到达的线程优先执行
2.优先执行阻塞队列的未执行任务,阻塞队列没有任务了才会判断是否要销毁线程
3.从答案1&2可以看到优越性,能充分利用阻塞队列缓存积压的待处理任务,然后实在扛不住了,会新创建额外的线程来处理,这些线程完成任务后还会积极帮忙处理阻塞队列的任务,合理的利用线程资源,避免频繁的创建和销毁线程。如果阻塞队列和最大线程数两个参数的优先级倒过来,那极有可能发生频繁创建和销毁线程的过程。
先回顾下线程池管理上的逻辑:
测试代码:
public class Test {
public static ThreadPoolExecutor pool = new ThreadPoolExecutor(1, 3,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(4),
Executors.defaultThreadFactory());
public static void main(String[] args) {
System.out.println("getPoolSize_getActiveCount_getCompletedTaskCount_getLargestPoolSize_getTaskCount_getQueue.size");
for (int i = 0; i < 7; i++) {
pool.execute(getCommand(i));
}
try {
Thread.sleep(15000);
pool.execute(getCommand(8));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private static Runnable getCommand(final int cc) {
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
for (int i = 0; i < 1; i++) {
System.out.println(String.format("%s_%s: %s_%s_%s_%s_%s_%s",cc,Thread.currentThread().getName(),pool.getPoolSize(), pool.getActiveCount(),
pool.getCompletedTaskCount(),pool.getLargestPoolSize(),pool.getTaskCount(),pool.getQueue().size()));
Thread.sleep(2000);
}
} catch (Exception e) {
}
}
};
return runnable;
}
}
执行结果:
0由第一个核心线程处理,1234进入阻塞队列,56由核心线程外的线程处理。
3个线程处理完当前任务后又同时消灭了阻塞队列中的任务123。
线程3再次消灭了阻塞队列的任务4。
阻塞队列空了之后,线程1和线程2被销毁,只剩下线程3作为核心线程处理了最后提交的任务8。