这里主要讲的是,阻塞队列和max线程,的顺序。哪个先?哪个后?
顺序
min——》阻塞队列——》max
解释
1.线程数量小于min,创建新的线程。
2.线程数量达到min之后,还有新的任务过来,那么就把新的任务放到阻塞队列里面去。//等任务完成之后,min里的线程,就可以继续处理新的任务了,当然,这个任务,是从阻塞队列里取的。
3.当任务数量达到阻塞队列的最大值之后,还有新的任务过来,那么就创建新的线程,让新的线程去处理新的任务。
4.最后一种情况,就是线程数量达到max之后,那么现在既不能创建新的线程,也不能入队列,那么怎么办?有2种方法1.丢弃2.阻塞入队列。
官方api文档解释
Queuing
Any BlockingQueue may be used to transfer and hold submitted tasks. The use of this queue interacts with pool sizing:
1.If fewer than corePoolSize threads are running, the Executor always prefers adding a new thread rather than queuing.
2.If corePoolSize or more threads are running, the Executor always prefers queuing a request rather than adding a new thread.
3.If a request cannot be queued, a new thread is created unless this would exceed maximumPoolSize, in which case, the task will be rejected.
上面的第四种情况,具体是怎么处理?
不管是1.丢弃2.阻塞入队列。都是通过线程池的拒绝参数来处理的。具体是,在拒绝参数的拒绝方法里,你可以:
1.丢弃
2.阻塞入队列
代码
/** 10个线程检查异步订单,当队列满了之后,等待 */
protected static Executor executor = new ThreadPoolExecutor(10 //min, 10 //max, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(1000), //阻塞队列
new RejectedExecutionHandler() { //拒绝参数
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { //拒绝方法
if (!executor.isShutdown()) { //如果没关闭,就阻塞入队列
try {
executor.getQueue().put(r);
} catch (InterruptedException e) {
log.error(e.getMessage(), e);
}
} //如果关闭,就丢弃
}
});
阻塞入队列,入的是哪一个队列?
就是线程池参数配置的阻塞队列。难道还有什么其他的队列吗?没有!
本质就是,阻塞入队列,即一旦阻塞队列数据被消费,有新的空间,就立马写入数据到阻塞队列。
丢弃
什么时候丢弃?
阻塞入队列?
什么时候阻塞入队列?其实这两个问题,得看应用场景。必须要处理的数据,就阻塞入队列。比如,支付系统的实名认证,数据必须要处理,那就阻塞入队列。
参考
官方api文档
最后
如果想要改变阻塞队列和max的顺序,怎么办?网上有开源的实现。
为什么java线程池默认是先阻塞队列,后max?
因为线程数量太多,机器本身也处理不过来,所以最佳实践,一般情况就是使用min线程数量在跑,在处理任务。处理不过来,就把任务丢到阻塞队列里去。再处理不过来,才创建新的线程,这是没有办法的办法。
因为创建太多的线程,反而不是什么好事,原因是线程切换,是非常耗资源的。
应用场景
支付系统的实名认证。