最近在使用阿里编码规约扫描代码(之前一个老的项目)时,发现代码里有爆BLOCKER级别的一个问题,如下图所示:
线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。手动创建线程池,效果会更好哦。
于是乎,我使用new Thread()方式创建了一个线程,之后P3C又爆出了另外一个建议:线程资源必须通过线程池提供,不允许在应用中自行显式创建线程。不要显式创建线程,请使用线程池。
那只能再换一种方式了,使用 ThreadPoolExecutor 线程池方式。如下代码所示,终于不再提示我了。
HandlerJobRunnable handlerJobRunnable = new HandlerJobRunnable(); // 构造一个线程池 ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 1, 10, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(1), new ThreadPoolExecutor.DiscardOldestPolicy()); threadPoolExecutor.execute(() -> { try { // 执行 方法 handlerJobRunnable.run(); } catch (Exception e) { e.printStackTrace(); }finally{ // 关闭线程池 threadPoolExecutor.shutdown(); } });
拓展
下面来看一下构造器,了解一下各个参数含义:
顺便总结一下每种线程创建的优缺点:
new Thread 方式
优势:显而易见的线程创建方式
缺点:每次都要new对象,当有大量请求时,数不清new了多少个对象了,如果不及时关闭会导致内存溢出,因此还要考虑线程管理等问题。
Executors工厂创建线程池
newCachedThreadPool:
创建一个可缓存线程池
优点:很灵活,弹性的线程池线程管理,用多少线程给多大的线程池,不用后及时回收,用则新建
缺点:一旦线程无限增长,会导致内存溢出。
newFixedThreadPool :
优点:创建一个固定大小线程池,超出的线程会在队列中等待。
缺点:不支持自定义拒绝策略,大小固定,难以扩展
newScheduledThreadPool :
优点:创建一个固定大小线程池,可以定时或周期性的执行任务。
缺点:任务是单线程方式执行,一旦一个任务失败其他任务也受影响。
newSingleThreadExecutor :
优点:创建一个单线程的线程池,保证线程的顺序执行
缺点:不适合并发。。不懂为什么这种操作要用线程池。。为什么不直接用队列
统一缺点:不支持自定义拒绝策略。
通过ThreadPoolExecutor创建线程池
优点:集上述优点于一身
缺点:目前还没有人说它有什么缺点,因为上述线程池的底层就是通过它来创建的,欢迎大佬留言补充哈。
完结!