线程生命周期和线程池--java进阶day16

1.线程生命周期总览

最顺畅的情况

新建:创建线程对象

当我们调用start后,线程只是进入就绪状态,要等线程抢到cpu执行权后,才是运行状态

当cpu被其他线程抢走执行权后,重新回到就绪状态

在运行状态时,遇到sleep方法,线程进入计时等待(休眠),当时间结束后,线程重新回到就绪状态(不是运行状态!)

在运行期间,遇到wait方法,线程进入无限等待,只有当其他线程使用notify才能将其唤醒,重新进入就绪状态

在运行期间,还有可能线程A被其他线程抢走执行权,并且其他线程上锁,

此时线程A无法获取到锁,进入阻塞状态,当其他线程释放锁后,线程A可以获取到锁后,重新进入就绪状态

线程状态都被定义在枚举类中,作为一种标记

2.线程池

之前我们都是直接创建线程来使用,但是这是极其不规范的行为

例如:当我们要执行一个任务时,系统创建线程,然后执行完任务,系统又把线程删除,实际上,执行任务花费的时间非常短,但是创建和删除线程对象浪费了大量时间

线程池里养了许多的线程,当有任务要执行时,我们从线程池里拿出一些线程,用完后再放回线程池,极大的缩减了时间

注意:不能使用JDK自带的线程池,因为里面的参数都是配置好的,不便于我们操作。应该使用自定义线程池

3.自定义线程池

使用ThreadPoolExecutor来创建线程池,里面共有七个参数需要我们指定

[1]参数1、2、3、4

参数1代表核心线程数量,就像餐馆里面的正式员工一样,主要工作都是由它们负责

参数2代表最大线程数量,即正式员工加上临时工的数量,当任务过多导致正式员工忙不过来时,可以招聘临时工负责顶上

参数3为空闲时间,参数4为时间单位,两者要搭配使用,假如我们输入60 秒

就代表60s之后要是还没有任务提交,临时工就会被销毁

[2]参数5、6、7

参数5代表任务队列,即指定排队人数,当所有员工都忙不过来时,可以指定一些顾客排队,等到其他任务做完后,再来执行排队的任务

参数6代表线程对象任务工厂,由该工厂专门创建线程对象,可以理解为招人渠道(参数6为固定代码)

参数7为拒绝策略,例如我们指定排队人数为5人,现在来了第六个人,此时就要使用参数7的拒绝策略,以什么样的方式拒绝新提交的任务

代码演示

我们设定核心线程为2个,临时工3个,最大线程数量为5,然后设定空闲时间为60s

参数4的单位并不是给字符串,而是给一个TImeUnit的枚举(类),然后可以任意选择时间单位

任务队列有两者选择,一种是有界队列,另一种是无界队列

有界队列需要指定参数(排队人数),而无界队列不需要参数,无界队列是没有界限的,想排多少排多少

但无界队列只是概念上的无界,它实际只能排21个亿左右的任务

参数6写一段固定代码即可

参数7指定拒绝策略,我们这里选择的拒绝策略是拒绝新提交的任务

submit方法用于提交任务,循环10次submit,相当于提交了10个任务

右键运行,我们会发现控制台只有正式员工在干活

将任务量调为13个后,发现控制台出现了临时工,说明在正式工和任务队列都排满之后才会招临时工

将任务调为15个后,所有临时工都已招聘

而将任务调为16个后,控制台报错,说明当任务数量大于“最大线程数量+任务队列”时,会触发拒绝策略

虽然控制台报错了,但是控制台其他线程都还在干活,所以,只是一条线程抛了异常,线程池还在,下次还可以正常使用

线程池细节

各种拒绝策略(使用第一种即可)

第四个拒绝策略绕过run方法提交任务,好比老板亲自上阵(不推荐)

总结

posted @ 2025-05-18 14:50  直実  阅读(45)  评论(0)    收藏  举报