在《阿里巴巴java开发手册》中指出了线程资源必须通过线程池提供,不允许在应用中自行显示的创建线程,这样一方面是线程的创建更加规范,可以合理控制开辟线程的数量;另一方面线程的细节管理交给线程池处理,优化了资源的开销。而线程池不允许使用Executors去创建,而要通过ThreadPoolExecutor方式,这一方面是由于jdk中Executor框架虽然提供了如newFixedThreadPool()、newSingleThreadExecutor()、newCachedThreadPool()等创建线程池的方法,但都有其局限性,不够灵活;另外由于前面几种方法内部也是通过ThreadPoolExecutor方式实现,使用ThreadPoolExecutor有助于大家明确线程池的运行规则,创建符合自己的业务场景需要的线程池,避免资源耗尽的风险。
代码示例:
public static void main(String[] args) { //创建线程池 ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 10, 1L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(1), new ThreadPoolExecutor.AbortPolicy()); //设置核心线程空闲超时时关闭,默认为false threadPoolExecutor.allowCoreThreadTimeOut(true); MonitorThread monitorThread = new MonitorThread(); threadPoolExecutor.execute(monitorThread); LOG.info("线程池中线程数目:{},队列中等待执行的任务数目:{},已执行完的任务数目:{}", cutExecutor.getPoolSize(), cutExecutor.getQueue().size(), cutExecutor.getCompletedTaskCount()); }
一、创建线程池
1.ThreadPoolExecutor提供了四个构造方法
注意:
“keepAliveTime”该参数默认对核心线程无效,如果想应用到核心线程,则需要打开配置:threadPoolExecutor.allowCoreThreadTimeOut(true);
二、线程池触发拒绝策略
和数据源连接池不一样,线程池除了初始大小和池子最大值,还多了一个阻塞队列来缓冲。
数据源连接池一般请求的连接数超过连接池的最大值的时候就会触发拒绝策略,策略一般是阻塞等待设置的时间或者直接抛异常。
而线程池的触发时机如下图:
如图,想要了解线程池什么时候触发拒绝粗略,需要明确上面三个参数的具体含义,是这三个参数总体协调的结果,而不是简单的超过最大线程数就会触发线程拒绝粗略,
当提交的任务数大于corePoolSize时,会优先放到队列缓冲区,只有填满了缓冲区后,才会判断当前运行的任务是否大于maxPoolSize,小于时会新建线程处理,大于时就触发了拒绝策略。
总结就是:当前提交任务数大于(maxPoolSize + queueCapacity)时就会触发线程池的拒绝策略了。