通过一次代码校验发现 线程池不建议使用Executors去创建,而是通过ThreadPoolExecutor方式的原因 顺便总结线程优缺点
首先用的是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>());
}
你会发现Executors的底层就是ThreadPoolExecutor。。只不过加了很多限制,剩下的自己翻源码去!!