阿里巴巴建议的线程池创建方式,你用上了吗?(代码片段)

Java知音_ Java知音_     2023-01-11     338

关键词:

点击关注公众号,实用技术文章及时了解

来源:blog.csdn.net/dabusiGin/

article/details/105327873

Executor是不建议的

Executors类为我们提供了各种类型的线程池,经常使用的工厂方法有:

public static ExecutorService newSingleThreadExecutor()
public static ExecutorService newFixedThreadPool(int nThreads)
public static ExecutorService newCachedThreadPool()
public static ScheduledExecutorService newSingleThreadScheduledExecutor()
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)

书写一段很简单的测试代码:

public class ThreadDemo 
 public static void main(String[] args) 
  ExecutorService es = Executors.newSingleThreadExecutor();
 

当我们用阿里巴巴的P3C检查代码时,会被教育的!!!!

阿里爸爸是不允许这么创建线程池的,上面的警告写的很明确“线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。”(PS:很难得在编译器中看到中文提示,对于英语不好的同学来说,简直是福音,喜极而泣!!!!)

强制使用ThreadPoolExecutor

我们使用ThreadPoolExecutor创建线程池:

public class ThreadDemo 
 public static void main(String[] args) 
  ExecutorService es = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS,
    new LinkedBlockingQueue<Runnable>(10), Executors.defaultThreadFactory(),
    new ThreadPoolExecutor.DiscardPolicy());
 

此时,再用P3C检查代码,终于没有报错了。

在华丽的分隔符之后,我们还是有必要从JDK源码的层面深挖一下其中的原理。

首先是静态方法newSingleThreadExecutor()newFixedThreadPool(int nThreads)newCachedThreadPool()。我们来看一下其源码实现(基于JDK8)。

public static ExecutorService newSingleThreadExecutor() 
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));


public static ExecutorService newFixedThreadPool(int nThreads) 
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());


public static ExecutorService newCachedThreadPool() 
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());

通过查看源码我们知道上述三种静态方法的内部实现均使用了ThreadPoolExecutor类。难怪阿里爸爸会建议通过ThreadPoolExecutor的方式实现,原来Executors类的静态方法也是用的它,只不过帮我们配了一些参数而已。

第二是ThreadPoolExecutor类的构造方法。既然现在要直接使用ThreadPoolExecutor类了,那么其中的初始化参数就要我们自己配了,了解其构造方法势在必行。

ThreadPoolExecutor类一共有四个构造方法,我们只需要了解之中的一个就可以了,因为其他三种构造方法只是帮我们配置了一些默认参数,最后还是调用了它。

public ThreadPoolExecutor(int corePoolSize,
            int maximumPoolSize,
            long keepAliveTime,
            TimeUnit unit,
            BlockingQueue<Runnable> workQueue,
            ThreadFactory threadFactory,
            RejectedExecutionHandler handler)

其中的参数含义是:

  • corePoolSize:线程池中的线程数量;

  • maximumPoolSize:线程池中的最大线程数量;

  • keepAliveTime:当线程池线程数量超过corePoolSize时,多余的空闲线程会在多长时间内被销毁;

  • unit:keepAliveTime的时间单位;

  • workQueue:任务队列,被提交但是尚未被执行的任务;

  • threadFactory:线程工厂,用于创建线程,一般情况下使用默认的,即Executors类的静态方法defaultThreadFactory();handler:拒绝策略。当任务太多来不及处理时,如何拒绝任务。

对于这些参数要有以下了解:

corePoolSize与maximumPoolSize的关系

首先corePoolSize肯定是 <= maximumPoolSize。

其他关系如下:

  • 若当前线程池中线程数 < corePoolSize,则每来一个任务就创建一个线程去执行;

  • 若当前线程池中线程数 >= corePoolSize,会尝试将任务添加到任务队列。如果添加成功,则任务会等待空闲线程将其取出并执行;

  • 若队列已满,且当前线程池中线程数 < maximumPoolSize,创建新的线程;

  • 若当前线程池中线程数 >= maximumPoolSize,则会采用拒绝策略(JDK提供了四种,下面会介绍到)。

注意:关系3是针对的有界队列,无界队列永远都不会满,所以只有前2种关系。

学习资料:Java进阶视频资源

workQueue

参数workQueue是指提交但未执行的任务队列。若当前线程池中线程数>=corePoolSize时,就会尝试将任务添加到任务队列中。主要有以下几种:

  • SynchronousQueue:直接提交队列。SynchronousQueue没有容量,所以实际上提交的任务不会被添加到任务队列,总是将新任务提交给线程执行,如果没有空闲的线程,则尝试创建新的线程,如果线程数量已经达到最大值(maximumPoolSize),则执行拒绝策略。

  • LinkedBlockingQueue:无界的任务队列。当有新的任务来到时,若系统的线程数小于corePoolSize,线程池会创建新的线程执行任务;当系统的线程数量等于corePoolSize后,因为是无界的任务队列,总是能成功将任务添加到任务队列中,所以线程数量不再增加。若任务创建的速度远大于任务处理的速度,无界队列会快速增长,直到内存耗尽。

handler

JDK内置了四种拒绝策略:

  • DiscardOldestPolicy策略:丢弃任务队列中最早添加的任务,并尝试提交当前任务;

  • CallerRunsPolicy策略:调用主线程执行被拒绝的任务,这提供了一种简单的反馈控制机制,将降低新任务的提交速度。

  • DiscardPolicy策略:默默丢弃无法处理的任务,不予任何处理。

  • AbortPolicy策略:直接抛出异常,阻止系统正常工作。

至此,我们直接new ThreadPoolExecutor类就不用慌了!!!!

推荐:

主流Java进阶技术(学习资料分享)

PS:因为公众号平台更改了推送规则,如果不想错过内容,记得读完点一下“在看”,加个“星标”,这样每次新文章推送才会第一时间出现在你的订阅列表里。点“在看”支持我们吧!

android为啥阿里android开发手册中,线程池不建议使用executors去创建?(代码片段)

Executors返回的线程池对象的弊端如下:FixedThreadPool和SingleThreadPool:允许的请求队列长度为Integer.MAX_VALUE,可能会堆积大量的请求,从而导致OOM;CachedThreadPool和ScheduledThreadPool:允许的创建线程数量为Integer.MAX_VALUE,可能会创... 查看详情

java~线程池的总结~续(代码片段)

...规则,规避资源耗尽的风险。ThreadPoolExecutor实现的线程池阿里巴巴的JAVA开发手册推荐用ThreadPoolExecutor创建线程池。来看看ThreadPoolExecutor创建线程池的api:publicThreadPoolExecutor(intcorePoolSize,intmaximumPoolSize,longkeepAliveTime,TimeUnitunit,BlockingQ... 查看详情

线程池(代码片段)

...推荐使用 ThreadPoolExecutor 构造函数创建线程池在《阿里巴巴Java开发手册》“并发处理”这一章节,明确指出线程资源必须通过线程池提供,不允许在应用中自行显示创建线程。为什么呢?使用线程池的好处是减少在... 查看详情

线程的三种创建方式你get了吗?(代码片段)

备战2022春招或暑期实习,祝大家每天进步亿点点!Java并发编程Day4本篇总结的是如何在Java中避免创建不必要的对象,后续会每日更新~关于《我们一起学Redis》、《我们一起学HarmonyOS》等知识点可以查看我的往期博客... 查看详情

阿里巴巴:禁止使用executors创建线程池!为什么啊?(代码片段)

​来源:​blog.csdn.net/dabusiGin/article/details/105327873/Executor是不建议的Executors类为我们提供了各种类型的线程池,经常使用的工厂方法有:publicstaticExecutorServicenewSingleThreadExecutor()publicstaticExecutorSer 查看详情

线程池之threadpoolexecutor(代码片段)

线程池之ThreadPoolExecutor+面试题线程池介绍线程池(ThreadPool):把一个或多个线程通过统一的方式进行调度和重复使用的技术,避免了因为线程过多而带来使用上的开销。为什么要使用线程池?可重复使用已有线程,避免对象创... 查看详情

阿里java编码规范记录

1.【强制】线程池资源必须通过线程池提供,不允许在应用中显示创建线程说明:使用线程池的好处是减少在创建和销毁线程上所消耗的时间及系统资源,解决资源不足的问题。如果不使用线程池,有可能造成系统创建大量同类... 查看详情

阿里编程规范不建议使用线程池,为什么?(代码片段)

什么是线程池?线程池可以通过池看出来是一个资源集,任何池的作用都大同小异,主要是用来减少资源创建、初始化的系统开销。创建线程很“贵”吗?是的。创建线程的代价是昂贵的。我们都知道系统中的每... 查看详情

idea对新建java线程池的建议

...bsp;ExecutorServicepool=Executors.newCachedThreadPool();    2建议的三种模板 A第一种,采用Apache的common.lang3的新建方式B第二种,采用线程池工厂的方式C第三种,采用Spring配置xml文件,配置线程池工厂 3建议的原因按照直接... 查看详情

executors介绍(代码片段)

《阿里巴巴java开发手册》线程池不使用Executors去创建,而是通过ThreadPoolExecutor的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。主要原因是使用Executors创建线程池不会传入这个参数而使用... 查看详情

如何优雅的使用和理解线程池(代码片段)

...开发的童鞋应该都或多或少了解过线程池,之前发布的《阿里巴巴Java手册》里也有一条:可见线程池的重要性。简单来说使用线程池有以下几个目的:线程是稀缺资源,不能频繁的创建。解耦作用;线程的创建于执行完全分开... 查看详情

创建线程的方式以及executors的四种线程池(代码片段)

创建线程有几种方式?面试常问的问题,一般回答3种方式,及格;如果你能具体的说4种,那你就满分了,第四种是通过Executors创建线程池。先来说说创建线程的3种方式:一、继承Thread类publicclassExtendsT... 查看详情

通过threadpoolexecutor源码分析线程池实现原理(代码片段)

...总结)。通过Executors创建线程池有很多局限性和隐患,在阿里巴巴《Java开发手册 查看详情

多线程(六):线程池(代码片段)

多线程(六):线程池线程池的定义线程池创建线程是懒加载的线程池优点线程池的创建方式(7种)线程池的创建方式①:创建固定个数的线程池自定义线程池行为线程池的创建方式②:创建带缓存的线程... 查看详情

java线程池threadpoolexecutor类使用详解(代码片段)

在《阿里巴巴java开发手册》中指出了线程资源必须通过线程池提供,不允许在应用中自行显示的创建线程,这样一方面是线程的创建更加规范,可以合理控制开辟线程的数量;另一方面线程的细节管理交给线程池处理,优化了... 查看详情

java线程池threadpoolexecutor类使用详解(代码片段)

在《阿里巴巴java开发手册》中指出了线程资源必须通过线程池提供,不允许在应用中自行显示的创建线程,这样一方面是线程的创建更加规范,可以合理控制开辟线程的数量;另一方面线程的细节管理交给线程池处理,优化了... 查看详情

阿里巴巴java开发规范手册

(六)并发处理  1、获取单例对象须要保证线程安全,其中的方法也要保证线程安全  2、创建线程或线程池时请指定有意义的线程名称,方便出错时回溯  3、线程资源必须通过线程池提供,不允许在应用中自行显示创建... 查看详情

线程八大基础核心一(创建线程的方式)(代码片段)

1.引子  在java多线程并发编程中,有八大基础核心。考考你:看看都有哪八大基础核心呢?它们分别是:   1.创建线程的方式   2.线程启动   3.线程停止   4.线程生命周期   5.线程相关的方法   6.线程相关的属性... 查看详情