ThreadPoolExecutor类的七大核心参数的意义: 1、int corePoolSize:核心线程数 2、int maximumPoolSize:最大线程数,最小大于1(当核心线程数和任务队列都满的时候,这个时候开始扩容线程) 3、long keepAliveTime:当线程池中的线程数大于核心线程数的时候,当空闲的时间大于unit时,则多余的线程将会被销毁只剩下核心线程数的数量,从maximumPoolsSize缩短到corePoolSize数目 4、TimeUnit unit:多余线程的空余时间 5、BlockingQueue<Runnable> workQueue:任务队列(阻塞队列)。类似银行里面的候客区 6、ThreadFactory threadFactory:线程工厂,用于创建线程,默认的即可 7、RejectedExecutionHandler handler:拒绝策略(当核心线程数和最大线程数和任务队列到达最大的时候,这个时候启动拒绝策略)
/**
* 自己创建线程池
*/
private static void createMyThreadPool() {
//手写线程池
ExecutorService myThreadPool = new ThreadPoolExecutor(
2,
5,
1L,
TimeUnit.SECONDS,
new LinkedBlockingQueue(3),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.DiscardPolicy());
try
{
for (int i = 1; i <= 9 ; i++) {
myThreadPool.execute(()->{
System.out.println(Thread.currentThread().getName()+"\t 执行业务");
});
}
}catch(Exception e){
e.printStackTrace();
}finally{
myThreadPool.shutdown();
}
}
线程的执行机制:
当调用execute()方法添加一个请求任务时,线程池会做如下判断: 1、如果正在运行的线程数量小于corePoolSize,那么马上创建线程运行这个任务; 2、如果正在运行的线程数量大于或等于corePoolSize,那么将这个任务放入队列; 3、如果这时候队列满了且正在运行的线程数量还小于maximumPoolSize,那么还是要创建非核心线程立刻运行这个任务; 4、如果队列满了且正在运行的线程数量大于或等于maximumPoolSize,那么线程池会启动饱和拒绝策略来执行。 5、当一个线程完成任务时,它会从队列中取下一个任务来执行。 6、当一个线程无事可做超过一定的时间(keepAliveTime)时,线程池会判断: 7、如果当前运行的线程数大于corePoolSize,那么这个线程就被停掉,所以线程池的所有任务完成后它最终会收缩到corePoolSize的大小。
阿里巴巴开发手册说明如下: 【强制】线程资源必须通过线程池提供,不允许在应用中自行显式创建线程。 说明:线程池的好处是减少在创建和销毁线程上所消耗的时间以及系统资源的开销,解决资源不足的问题。 如果不使用线程池,有可能造成系统创建大量同类线程而导致消耗完内存或者“过度切换”的问题。 【强制】线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。 说明:Executors 返回的线程池对象的弊端如下: 1) FixedThreadPool 和 SingleThreadPool: 允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。 2) CachedThreadPool: 允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM