多线程——线程池
课程:
什么是线程池
可以自己实现这个功能,自己写一个线程池
jdk也给提供了线程池
为什么要有线程池
Executor框架
任务:就是代码
执行:谁去执行这个代码,之前是Thread执行的,
thread:
Executor:
Executor框架的接口与类结构
什么是juc
传统的java实现线程:
Thread类和Runnable都是java,lang包下的。
jdk从1.5开始,提供了新的三个包,简称为juc,这三个包用来实现并发编程的:
Executor框架结构:
实现:
Executors
像是Arrays:一个接口名+s, 是表示jdk里的对于这个接口类型的一个工具类的包装。
上面创建的时候要传很多参数,所以用这个工具类,不用去传参数直接获取想要的线程池,这种里面参数是不能修改的了,上面的可以修改我们想要的参数:
源码:
接收的接口:
线程池的七大参数解读
核心线程数
允许核心线程数超时allowCoreThreadTimeOut():
值默认是false, 永远都在池中不会被销毁
如果想让核心线程数在没有任务的时候也把他销毁:
设置为true:
这时候这个方法没有返回值,无法打印:
需要提交任务之后,才有线程
当我们提交任务之后,线程池中才会创建一个线程
想创建后立马创建线程:
阻塞队列
先暂时理解下,后面详细讲
先理解一个容器,可以往里面放数据,从里面取数据。先做个粗略的理解。
设置容量为自定义,如下设置为5:
最大线程数
池中最多能有多少个线程
不停提交任务,核心线程数用完,继续提交就存到队列里,队列满了再提交,就会再启动线程,如下设置了10个,那么就可以再临时创建10-5(核心)=5个线程
空闲线程超时时间和时间单位
上面那个如果设置了,核心线程也会被清理。
不设置就是清理非核心线程。
单位:设置的
如下:
就是5个非核心线程如果是空闲状态,空闲了15s,那么这5个非核心线程就会被销毁。
线程工厂
如下:
看源码:
线程工厂是一个接口:
有一个抽象方法:
存一个runnable, 给他创建一个线程返回
接口默认在jdk并发包里有两个实现:还有一个子实现:
找包对的,其他都不是并发包下的
默认用这两个实现就可以了:
这里用的工具类里的方法获取:
点进去看源码:
他就是给我们创建了一个默认的线程工厂的实现:
使用获取子类的线程工厂:
default线程工厂实现
点进去:
实现了接口,覆盖了newThread方法:
源码解读:
597:线程池个数编号,原子类后面会将
598:线程组
599:线程的编号,也是原子类,初始值是1
600:线程的名字的前缀
构造方法:
把线程组进行一个初始化,给线程名字前缀初始化
创建线程:
new一个线程:
参数:线程组,runnable,线程名字前缀拼上编号,栈的大小
线程如果是守护线程,改成非守护线程
线程优先级如果不是5,把优先级改成5
返回new的这个线程。
子类线程工厂实现
继承了default,default里有的东西相当于继承过来了。
首先继承了构造方法,super一下,把default里构造方法东西继承过来。
然后自己做了一些判断
new线程时:
用了父类的,实现的时候做了一些安全的检查
所以这个线程工厂上面有一些说明:
和当前线程有一些相同权限的线程工厂
自定义线程工厂
使用:
拒绝策略
拒绝策略参数源码:
参数位置:
拒绝策略是一个接口:
参数:要执行的任务,线程池对象
默认的实现策略有四个:
策略一AbortPolicy
使用:
源码:
实现拒绝策略接口,覆盖方法,
方法里就是抛异常:信息在异常中打印一下
异常是运行时异常:
所以可以try catch, 如果看见这个异常就可以额外处理
运行下用例:
提交第四个已经抛异常了:
记录的信息:
把runnable和线程池的信息打印了一下:
策略二:
不抛异常,有风险也不知道
使用:
源码:
实现接口,覆盖方法,方法里是空的,啥事都不做,所以当你任务超过他容量,那么这个是什么都不干,丢弃掉
代码演示:
运行结果:
有一个线程没被执行,抛弃掉了
策略三
丢弃最老的那个任务,执行当前的任务。
这个策略其实也是给丢掉。所以用的也不多。通常业务不多允许数据丢掉。
使用:
也是提交四个任务,分析:
一个核心线程在执行,队列有两个,提交了四个:
提交四的时候,会把老的丢弃,老的任务是2,所以会把2丢弃。
运行结果:
源码:
实现接口,覆盖方法:
如果线程池没有关闭,首先从线程池里拿到他的任务队列,调用poll方法,相当于给队列里移除一个,是队列的头部那个。
老任务删除,再把新任务提交给线程池。
策略四
就是线程池来执行任务,当线程池已经满了,就用调用线程执行,比如main方法的线程去执行。
代码演示:
运行结果:
线程4是由main线程执行的:
策略源码:
实现接口,覆盖方法:
方法: e线程池有没有关闭,如果没有关闭,直接调runnable的run方法,直接执行这个方法相当于:没有走线程,通过main方法调用的, main方法直接调线程里的run方法。
自定义拒绝策略
同样实现接口,覆盖方法