线程池技术的使用
1.创建线程池(不使用)
ExecutorService threadPool1 = Executors.newFixedThreadPool(3);// 固定大小
ExecutorService threadPool2 = Executors.newCachedThreadPool();//可以弹性伸缩的线程池,遇强则强 ExecutorService threadPool3 = Executors.newSingleThreadExecutor();// 只有一个
这种办法创建的线程池,存在弊端(阿里原话)
1)FixedThreadPool 和 SingleThreadPool:
允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。
2)CachedThreadPool 和 ScheduledThreadPool:
允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM。
底层这几种创建方式都是一样的:
Executors.newFixedThreadPool(3)底层为:
return new **ThreadPoolExecutor**(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
Executors.newCachedThreadPool()底层为:
return new **ThreadPoolExecutor**(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
Executors.newSingleThreadExecutor()底层为:
new **ThreadPoolExecutor**(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>())
LinkedBlockingQueue都没指定大小那默认就是最大整数。
2.推荐创建方法(推荐)
//获取当前计算机或服务器的线程数,
public class ThreadPoolTec {
public static void main(String[] args) {
//推荐的线程池的创建方法
/**
* 最多可以存在的人,maximumPoolSize + LinkedBlockingDeque的容量
*触发非活跃线程变为活跃的方法是:当前任务数量大于最大线程池容量,每超一个则激活一个,直到都被激活
* // 拒绝策略说明:
* // 1. AbortPolicy (默认的:队列满了,就丢弃任务抛出异常!)
* // 2. CallerRunsPolicy(哪来的回哪去? 谁叫你来的,你就去哪里处理)
* // 3. DiscardOldestPolicy (尝试将最早进入对立与的人任务删除,尝试加入队列)
* // 4. DiscardPolicy (队列满了任务也会丢弃,不抛出异常)
*/
Integer processors = Runtime.getRuntime().availableProcessors());
ExecutorService threadPool = new ThreadPoolExecutor(
2,//核心活跃线程数,类比银行两个柜台一直保持营业
processors ,//线程池最大大小,类比银行共5个柜台可以营业
2L,//超时回收空闲的线程,类比有三个非活跃线程处于活跃状态,在一定时间还未接到任务就进入非活跃状态(就是不营业了)
TimeUnit.SECONDS,//时间单位
new LinkedBlockingDeque<>(3),//存放等待任务的队列,类比为银行的候客区,不指定大小的话就是最大整数
Executors.defaultThreadFactory(),// 线程工厂,不修改!用来创建
new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略,即候客区满了,不再允许其他人排队了
);
try {
for(int j=1;j<=8;j++){
threadPool.execute(()->{
System.out.println(Thread.currentThread().getName()+"is running………………");
});
}
} catch (Exception e) {
e.printStackTrace();
}finally {
threadPool.shutdown();
}
}
}
这里几点说明:
1.创建线程池最大线程数与运行机器的线程数一致是最大利用资源。
Runtime.getRuntime().availableProcessors());就是获取当前机器的最大线程数
2.任务排队的队列要指定大小,new LinkedBlockingDeque<>(3),这样就不会太多等待的。
3.绝句策略依具体要求而定,我采用new ThreadPoolExecutor.CallerRunsPolicy()
4.注意多线程的执行,采用lamda方式写得:
for(int j=1;j<=8;j++){
threadPool.execute(()->{
System.out.println(Thread.currentThread().getName()+“is running………………”);
});
}
ThreadPoolExecutor 底层工作原理:
拒绝策略流程图: