2.为什么推荐使用原生方式创建线程池?

线程池的创建

创建线程池的方式一共有八种,

 

 

 

但万变不离其宗,这个宗就是原生创建线程池的方式,这种方式也是阿里极力推荐的一种。在阿里巴巴Java开发手册的第七章第四小节中这样写道,线程时不允许一个executors去创建,而是通过threadpoolExecutor的方式去创建,其他的创建方式有资源耗尽的风险。

 

 

后续章节再介绍其他创建方式时也会提到,这是上一节展示的线程池核心UML类图,从图中我们可以看到,能实例化的只有这两个

 

 

 

 

 

 

 

 

Threadpoolexecutor和scheduledthreadpoolexecutor,其中有一个类是线程池的核心类,它就是threadpoolexcuteor,它一共有四个构造方法,不过都大同小异。最后一个构造方法参数最多,我们就从他开始,该方法一共有七个参数,七个参数的含义如图所示,

 

 

 

 

 

 

corepoolsize。

核心线程数具体什么意思?把接下来的三个参数看完,一起说,Maximumpoolsize,最大线程数,

Keepalivetime,空闲线程存活时间,Unite,时间单位。这四个参数要一起看才更容易理解。这里我把四个参数都列举出来,并给他们附上值。

 

 

核心线程数是十,最大线程数是25,空闲线程存活时间是10,时间单位是timeunit..seconds也就是秒结和第三个参数合起来就是空闲线程的存活时间是十秒,十秒内没工作就会被销毁,如果空闲时间是零的话,空闲线程不会被销毁。所有参数都附上了,

 

 

直接下来我们就来创建这样一个线程池,首先是核心线程,事实表示线程池中有十个核心线程,

出,好处就是只要线程池不关闭,它就不会被销毁。

 

 

 

再来看第二个参数,最大线程数是25,表示线程池中最多允许有25个线程,那么在这25个线程当中,除去核心线程之外的线程是什么?是非核心线程,

 

 

 

非核心线程没有执行任务的话是要被清理的,在被清理之前能存活多久取决于第三个参数和第四个参数,

 

 

 

这是线程池中所有线程都在工作的场景,

 

 

 

当任务都执行完以后,

 

 

 

所有线程都成了空闲线程。

 

 

 

当然了,还是分核心和非核心,只不过再过十秒,

如果非核心线程门还没有工作,那就要被销毁,剩下的都是核心线程。

 

 

 

 

 

 

到这里,相信这四个参数你已经懂了

workqueue

workqueue、任务队列、存放任务的容器、提交给线程池的任务都存在这儿,线程池中的线程们也都是在这儿领取的任务,

 

 

 

我一般用的是linkedBlockingqueue,链式阻塞队列,这是一个基于链表的阻塞队列

 

 

 

.还有一个常用的是arrayblockingqueue数组阻塞队列,这是一个基于数组的阻塞队列。除此以外,大家还可以尝试其他的阻塞队列。

 

 

 

 

threadfactory线程工厂

threadfactory线程工厂,顾名思义,可以指定线程该如何生产,它是一个接口,实现它里面new thread()方法可以自定义线程的相关设置,例如我们可以指定线程名称,还可以指定线程是否为后台线程等等其他一些设置。

 

 

 

 

如果你不想自定义线程工厂,那么你也可以使用executeers内中的默认线程工厂。实际开发中我一般自定义得多,因为可以自定义线程名称,方便我后续查看日志。

 

 

 Handler任务拒绝策略

再来看最后一个参数,Handler任务拒绝策略。

 

 

 

在什么情况下我们提交给限制时的任务会被拒绝?同时满足以下这四种情况,我们提交给线程池的任务。会被拒绝。

第一种情况,线程池中的线程已满,

第二种情况,无法再继续扩容,

 

 

 

 

 

 

 

第三种情况,没有空闲线程,所有的线程都在执行任务,

 

 

 

第四种情况,任务队列已满,无法再存入新任务。

 

 

 

同时满足这四个条件时,我们提交给线程池的任务才会被拒绝。

线程池拒绝我们的方式也有四种,如图所示,这里就不再展开讲了,或许会单独出一个章节来讲任务拒绝策略,

呆会儿我们就用默认的拒绝策略回到构造方法,所有的参数也介绍完毕,接下来使用原生方法创建线程池。

线程工厂创建

我们先制定一个线程工厂,定义一个类customthreadfactory,实现threadfactory接口,重写new rhread方法的方法,定义一个计数器atomicinteger类型,这样就不会出现线程安全问题,初始值为一,该计数器用在线程名称中,给线程编号创建线程。

 

 

实例并指定任务自定义线程名称,每创建一个线程,

计数器递增一次,最后返回线程实例自定义线程工厂编写完成。

任务编写

接下来编写一个任务,任务内容是输出当前线程名称,我们来执行该任务。首先创建出三个任务,然后创建一个线程池,核心线程数为十,最大线程数为25,空闲线程存活时间为什,时间单位为秒。任务队列采用链式阻塞队列,线程工厂为刚刚自定义的线程工厂。任务拒绝策略采用的是默认任务拒绝策略。接下来像现实中提交任务,最后别忘了关闭线程池。至此main方法编写完成,整个例子也编写完成。

 

 

 

执行程序,观察执行结果。从执行结果来看,程序输出线程1,2,3,证明我们自定义的线程工厂生效了,使用原生方式创建线程池。成功最后总结一下本节的内容,本节介绍了如何使用原生方式创建线程直,这种方式是阿里极力推荐的一种,也是我日常开发中使用的最多的一种。

 

posted @ 2022-03-17 16:43  小陈子博客  阅读(365)  评论(0编辑  收藏  举报