今天在用P3C检查代码的时候发现这样一个警告:
首先用的是new Thread
public void doSummaryJob() throws Exception {
try{
HandlerMappingSummaryJobRunnable handlerMappingSummaryJobRunnable = new HandlerMappingSummaryJobRunnable();
Thread summaryJobThread = new Thread(handlerMappingSummaryJobRunnable);
summaryJobThread.start();
}catch(Exception e){
throw new Exception(HandlerMappingStaticValue.LOG_DO_SUMMARY_JOB_ERROR+e.getMessage());
}
}
然后爆出下面的建议
于是我改成Executors工厂创建线程池
HandlerMappingSummaryJobRunnable handlerMappingSummaryJobRunnable = new HandlerMappingSummaryJobRunnable();
// 定义一个线程池
ExecutorService executor = Executors.newCachedThreadPool();
executor.execute(() -> {
try {
handlerMappingSummaryJobRunnable.run();//执行 方法
} catch (Exception e) {
e.printStackTrace();
}finally{
executor.shutdown();// 关闭线程池
}
});
继续爆出下面的问题
线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
最终我使用ThreadPoolExecutor
//构造一个线程池
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
1,1,10,TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(1),
new ThreadPoolExecutor.DiscardOldestPolicy());
threadPool.execute(() -> {
try {
handlerMappingSummaryJobRunnable.run();//执行 方法
} catch (Exception e) {
e.printStackTrace();
}finally{
threadPool.shutdown();// 关闭线程池
}
});
阿里爸爸终于不再教育我了。。。
下面来看一下构造器,了解一下参数含义
// public ThreadPoolExecutor(
// int corePoolSize, - 线程池核心池的大小。
// int maximumPoolSize, - 线程池的最大线程数。
// long keepAliveTime, - 当线程数大于核心时,此为终止前多余的空闲线程等待新任务的最长时间。
// TimeUnit unit, - keepAliveTime 的时间单位。
// BlockingQueue<Runnable> workQueue, - 用来储存等待执行任务的队列。
// ThreadFactory threadFactory, - 线程工厂。
// RejectedExecutionHandler handler) - 拒绝策略。
由此开始简要概述一下创建线程的几种方式及优劣
new Thread 方式
优势:显而易见的线程创建方式
缺点:每次都要new对象,当有大量请求时,数不清new了多少个对象了,如果不及时关闭会导致内存溢出,因此还要考虑线程管理等问题。
Executors工厂创建线程池
newCachedThreadPool:
创建一个可缓存线程池
优点:很灵活,弹性的线程池线程管理,用多少线程给多大的线程池,不用后及时回收,用则新建
缺点:一旦线程无限增长,会导致内存溢出。
newFixedThreadPool :
优点:创建一个固定大小线程池,超出的线程会在队列中等待。
缺点:不支持自定义拒绝策略,大小固定,难以扩展
newScheduledThreadPool :
优点:创建一个固定大小线程池,可以定时或周期性的执行任务。
缺点:任务是单线程方式执行,一旦一个任务失败其他任务也受影响
newSingleThreadExecutor :
优点:创建一个单线程的线程池,保证线程的顺序执行
缺点:不适合并发。。不懂为什么这种操作要用线程池。。为什么不直接用队列
统一缺点:不支持自定义拒绝策略。
通过ThreadPoolExecutor创建线程池
优点:集上述优点于一身
缺点:没发现缺点,因为上述线程池的底层就是通过它来创建的。。哈哈哈
上源码举个例子!
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}