首页 > 编程知识 正文

线程池源码解析,工厂类java

时间:2023-05-06 20:57:13 阅读:42495 作者:3059

多线程的软件设计方法确实可以最大限度地发挥现代多核处理器的计算能力,提高生产系统的吞吐量和性能。 但是,如果在不进行控制或管理的情况下随意使用线程,则可能会对系统的性能产生不良影响。 因此,生产通常使用线程池来管理线程的创建。 无限创建线程的缺陷首先线程是一个比进程更轻的工具,但创建和关闭线程仍然需要时间,频繁创建和销毁线程会导致创建和销毁线程

其次的线程本身也占用内存空间。 如果不减少线程的数量,大量线程将占用宝贵的内存资源,如果处理不当,可能会导致内存溢出异常。 否则,大量线程的回收会给GC带来很大压力,延长GC的停止时间。

因此对于线程的使用必须掌握一次。 在有限的范围内,增加线程的数量可以显著提高系统的吞吐量,但超出此范围时,大量线程会破坏APP应用程序系统。

JDK并行执行器框架必须部署线程池,以减少在多线程并发期间创建和销毁线程所导致的系统开销。 线程池的基本功能是重用线程。 JDK提供了一个执行程序框架,帮助开发人员有效地执行线程控制。 其核心成员为Executor、ExecutorService、AbstractExecutorService、ThreadPoolExecutorThreadPoolExecutor继承了AbstractExecutorService类。AbstractExecutorService类实现了ExecutorService接口、ExecutorService的父接口Executor

ThreadPoolExecutor

所有这些成员都包含在java.util.concurrent包中,成员继承体系如下图:工具类、Executors类充当线程池工厂

//固定大小的线程池publicstaticexecutorservicenewfixedthreadpool (int nThreads ) returnnewthreadpoolexecutor ) nthreads,nthreadpolexexecutor 000 //单线程池publicstaticexecutorservicenewsinglethreadexecutor ({ returnnewfinalizabledelegatedexecutorservice } ) (new thread powecutor xecutor vice time unit.milliseconds, new linkedblockingqueuerunnable (//缓存线程池publicstaticexecutorservicenewcachedthreadpool ({ returnewthreadpoolexecutoool ) //单线程时间线程池publicstaticscheduledexecutorservicenewsinglethreadscheduledexecutor ({ returnewdelegatedscheduledexexecutor } { returnnewdelegatedschedexecutorservice//定时线程池publicstaticscheduledexecutorservicenewscheduledthr

eadPool(int corePoolSize) { return new ScheduledThreadPoolExecutor(corePoolSize); }

以上工厂方法分别返回具有不同工作特性的线程池,这些线程池工厂方法的具体说明如下:

newFixedThreadPool(int nThreads)方法
该方法返回一个固定线程数的线程池,该线程池中的线程数量始终不变。当有一个新任务提交时,线程池中若有空闲线程,则立即执行,若没有,则新的任务会被暂时存在一个任务队列中,待有线程空闲时,便处理在任务队列中的任务。newSingleThreadExecutor()方法
该方法返回一个只有一个线程的线程池。若多余的一个任务提交到该线程池,任务会被保存在一个任务队列中,待线程空闲,按照先入先出的顺序执行队列中的任务。newCachedThreadPool()方法
该方法返回一个可根据实际情况调整线程数量的线程池。线程池的线程数量不确定,但若有空闲线程可以复用,则会优先使用可复用的线程。若所有的线程均在工作,又有新的任务提交,则会创建新的线程处理任务。所有的线程在当前任务执行完毕后,将返回线程池进行复用,当空闲线程在指定的时间内(60s)无执行任务时被回收。newSingleThreadScheduledExecutor()方法
该方法返回一个ScheduledExecutorService对象,线程池大小为1。ScheduledExecutorService接口在ExecutorService接口之上扩展了在给定时间执行某任务的功能,如果在某个固定的延时之后执行,或者周期性执行某个任务。newScheduledThreadPool(int corePoolSize)方法
该方法也返回一个ScheduledExecutorService对象,但该线程池可以指定线程数量。

阿里巴巴JAVA开发手册关于创建线程池有这样的描述:
【强制】线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样
的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。

为什么阿里大厂强制不允许使用Executors创建线程池呢,我们再回顾一下Executors工厂类创建的线程池的方法,无论是newFixedThreadPool(int nThreads),newSingleThreadExecutor()或者是newCachedThreadPool()创建的线程池的方法,其内部均实现使用了ThreadPoolExecutor的构造函数,从以上线程池的实现代码可以看到,他们都是对ThreadPoolExecutor类的一个封装。

为何ThreadPoolExecutor类有如此强大的功能呢,我们看一下ThreadPoolExecutor类最重要的构造函数:

public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) { if (corePoolSize < 0 || maximumPoolSize <= 0 || maximumPoolSize < corePoolSize || keepAliveTime < 0) throw new IllegalArgumentException(); if (workQueue == null || threadFactory == null || handler == null) throw new NullPointerException(); this.corePoolSize = corePoolSize; this.maximumPoolSize = maximumPoolSize; this.workQueue = workQueue; this.keepAliveTime = unit.toNanos(keepAliveTime); this.threadFactory = threadFactory; this.handler = handler; }

函数参数含义如下:

corePoolSize 指定线程池中的核心线程数量maximumPoolSize 线程池中允许的最大线程数keepAliveTime 线程空闲时的存活时间 即超过corePoolSize的空闲线程在多长时间会被销毁unit keepAliveTime的时间单位workQueue 任务队列,用来保存被提交但尚未被执行的任务threadFactory 线程工厂,一般用默认即可,通过自定义的线程工厂可以给每个新建的线程设置一个具有识别度的线程名handler 拒绝策略 当任务太多来不及处理,如何拒绝任务

以上参数中,大部分都很简单容易理解,至于workQueue 任务队列,threadFactory 线程工厂,handler 拒绝策略的详细内容由于篇幅过长如果想了解可以移步博客尾部参看另一篇博客。

回到为什么阿里大厂强制不允许使用Executors创建线程池这个问题呢,我们回顾一下newFixedThreadPool(int nThreads)方法实现。它返回了一个corePoolSize和maximumPoolSize大小一样的,并且使用了LinkedBlockingQueue任务队列的线程池。因为对于固定大小的线程池而言,不存在线程数量上的动态变化,因此corePoolSize和maximumPoolSize可以相等。同时它使用无界队列存放无法立即执行的任务。当任务提交非常频繁的时候,该队列可能迅速膨胀,从而耗尽系统资源。

回顾一下newSingleThreadExecutor()方法实现返回的单线程线程池,是newFixedThreadPool(int nThreads)方法的一种退化,只是简单地将线程池的线程数量设置为1,等同于newFixedThreadPool(1)。

回顾一下newCachedThreadPool()方法实现返回的corePoolSize为0,maximumPoolSize为无穷大的线程池,这意味着在没有任务时,该线程池内无线程,而当任务被提交时,该线程池会使用空闲的线程执行任务。若无空闲线程,则将任务加入SynchronousQueue队列,而SynchronousQueue队列时一种直接提交的队列,它总会迫使线程池增加新的线程执行任务。当任务执行完毕后,由于corePoolSize为0,因此空闲线程又会在指定时间内(60秒)被回收。对于newCachedThreadPool(),如果同时有大量任务被提交,而任务的执行又不那么快时,那么系统便会开启等量的线程处理任务,这样做可能会因为过多创建线程耗尽系统资源。

ThreadPoolExecutor 相关友情链接 ThreadPoolExecutor 构造函数参数解析
参数解析包含了workQueue任务队列,threadFactory线程工厂,handler拒绝策略参数详解与案例ThreadPoolExecutor构造函数自定义线程池
Spring Boot项目通过构造函数方式自定义线程池案例与线程池大小数量优化控制Java扩展线程池追踪任务执行信息以及耗时情况
自定义一个线程池继承了ThreadPoolExecutor,然后重写beforeExecute,afterExecute,terminated方法实现对线程池运行状态的跟踪,了解线程池的具体使用情况以及每个线程实行耗时信息。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。