Executors提供了三个经典的线程池创建方式
ExecutorService threadPool = Executors.newFixedThreadPool(int)
ExecutorService threadPool = Executors.newSingleThreadPool()
ExecutorService threadPool = Executors.newCachedThreadPool(int)
那我们在工作中到底用哪一个呢?
答案是我们在生产上只能用自定义的
根据图中我们可以发现他们得底层实现都是用了ThreadPoolExecutor,然而第五个参数使用到的阻塞队列默认值是Integer.MAX_VALUE,也就是
2147483647,这样就相当于是一个无界的队列。所有的请求都往里塞,最终造成OOM。
根据阿里编码规范也可以看出
参数说明
线程池底层实现的7大参数
1.corePoolSize:线程池中的常驻核心线程数
2.maximumPoolSize:线程池能够容纳同时执行的最大线程数,此值必须大于等于1
3.keepAliveTime:多余的空闲线程的存活时间
4.unit:keepAliveTime的单位
5.workQueue:任务队列,被提交但尚未被执行的任务。
6.threadFactory:表示生成线程池中工作线程的线程工厂,用于创建线程一般用默认
7.handler:拒绝策略,表示当队列满了并且工作线程大于等于线程池的最大线程数
工作原理
线程池的底层工作原理
core基本线程数,当线程数大于corePoolSize时,多余线程将转入阻塞队列,阻塞队列也满了之后
将扩容到maximumPoolSize数。maximumPoolSize也满了之后将采取拒绝策略。
当线程数小了之后,根据设定的空闲线程存活时间将线程总容量回缩到corePoolSize
手动实现
* 线程池demo
* @author t
* 实际工作中对多线程的使用都是线程池,不会显示的创建线程
* 而使用传统方式的方法创建线程池容易造成oom
*/
public class ThreadPoolDemo {
2,
5,
1,
TimeUnit.SECONDS,
new LinkedBlockingDeque<>(3),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
try {
for (int i = 1; i <= 10; i++) {
final int num = i;
threadPool.execute(() -> {
//打印当前线程名称
//暂停一会线程
System.out.println("序号 "+num+" "+Thread.currentThread().getName()+" \t 办理业务");
});
}
}catch (Exception e){
e.printStackTrace();
}finally {
threadPool.shutdown();
}
}
}
运行结果
注意:根据机器配置不同运行效果也不同,本来应该是超过最大线程数(maximumPoolSize+队列大小)就会触发拒绝策略,但是由于机器处理速度
能够处理的过来,所以没有报错。
线程暂停1秒,9个线程的运行结果
作者:ushowtime
原文地址:https://www.ushowtime.cn/blog/p/50
来源:https://www.cnblogs.com/ushowtime/p/12502797.html