Java之线程池
2022-07-04 14:38:00 30 举报
AI智能生成
Java线程池是一种管理线程的机制,它可以在需要时创建新的线程,并在不需要时回收和重用这些线程。线程池的主要目的是提高系统性能,因为创建和销毁线程都需要消耗系统资源。通过使用线程池,我们可以减少线程创建和销毁的次数,从而降低系统开销。 Java提供了两种类型的线程池:固定大小的线程池和可缓存的线程池。固定大小的线程池包含一定数量的线程,当有任务提交时,如果线程池中有空闲线程,则直接执行任务;如果没有空闲线程,则将任务放入队列等待。可缓存的线程池可以根据需要创建新线程,但如果当前线程数超过最大值,则会回收空闲线程。
作者其他创作
大纲/内容
好处
降低资源消耗
通过重复利用已创建的线程降低线程创建和销毁造成的消耗
提高响应速度
当任务到达时,任务可以不需要等到线程创建就能立即执行
提高线程的可管理性
进行统一分配、调优和监控
六大参数
corePoolSize
线程池中核心线程的数量
默认线程池中没线程,等任务来了才创建线程
如调用了预创建线程prestartAllCoreThreads(),线程池会提前创建并启动所有核心线程
maxPoolSize
线程池中允许的最大线程数
如果队列满了,并且已创建的线程数小于最大线程数,则线程池会再创建新的线程执行任务
如果是无界队列则这个参数没有效果
如果是无界队列则这个参数没有效果
添加线程规则
corePoolSize:核心线程数设为5;maxPoolSize:最大线程数设为了10;workQueue队列设为了100;
线程池初始化的时候,线程池中没有线程;
线程池初始化的时候,线程池中没有线程;
此时来了个任务,线程池就会创建一个线程
如果后面又来了个任务,(无论线程池中是否有闲置的线程,只要,此时线程池中线程数<=5)线程池还会创建一个线程;
按照这样的规则,如果来了5个任务后,线程池中的线程数就达到了5
线程池中的这5个线程,通常会一直存活:即,即使这5个线程都处于空闲状态,其也会一直存在
如果线程池中的5个线程都在执行任务,没有空闲的线程;但是,此时又来了一些任务,其会把任务放在workQueue队列中去,进行排队
如果任务一下来了很多,把队列也排满了;而且,任务继续来的话
那么,线程池会判断,如果此时线程数<10:那么,线程池就会继续创建线程;
如果,队列也满了,线程数也达到了10;如果此时,任务继续来的话,这个任务就会被拒绝
keepAliveTime
线程空闲的时间
unit
keepAliveTime的单位
如果线程池当前线程数,多于corePoolSize
而且,多余的线程空闲了
并且空闲的时间,超过了我们设置的KeepAliveTime
那么这些多余的非核心线程,就会被回收
而且,多余的线程空闲了
并且空闲的时间,超过了我们设置的KeepAliveTime
那么这些多余的非核心线程,就会被回收
allowCoreThreadTimeOut
默认为false,若开启为true,则此时线程池中不论核心线程还是非核心线程,只要其空闲时间达到keepAliveTime都会被回收
workQueue
用来保存等待执行的任务的阻塞队列
使用的阻塞队列
有界队列
ArrayBlockingQueue
无界队列
LinkedBlockingQueue
最大线程池没用
防止流量突增
OOM异常
PriorityBlockingQueue
直接交接
SynchronousQueue
队列不存线程,所以最大线程数要大
threadFactory
用于设置创建线程的工厂
DefaultThreadFactory
handler
RejectedExecutionHandler,线程池的拒绝策略
分类
AbortPolicy :直接抛出异常,默认策略
CallerRunsPolicy :用调用者所在的线程来执行任务
DiscardOldestPolicy :丢弃阻塞队列中靠最前的任务,并执行当前任务
Discard Policy:直接丢弃任务
默认or自定义
Executors创建线程池
newSingleThreadExecutor
使用单个worker线程的Executor
分析
corePoolSize、maximumPoolSize被设置为1
使用“无界”队列LinkedBlockingQueue作为workerQueue
阻塞队列长度过长,造成oom
newFixedThreadPool
可重用固定线程数的线程池
分析
corePoolSize和maximumPoolSize一致
使用“无界”队列LinkedBlockingQueue作为workerQueue
maximumPoolSize、keepAliveTime、RejectedExecutionHandler无效
阻塞队列长度过长,造成oom
newCachedThreadPool
会根据需要创建新线程的线程池
分析
corePoolSize=0 maximumPoolSize=Integer.MAX_VALUE
SynchronousQueue作为WorkerQueue
MaximumPoolSize=Integer.MAX_VALUE 创建大量线程造成OOM
如果主线程提交任务的速度高于maximumPool中线程处理任务的速度时,Cached ThreadPool会不断创建新线程,可能会耗尽CPU和内存资源
newScheduledThreadPool
延迟周期性的线程池
分析
maximumPoolSize=Integer.MAX_VALUE
DelayedWorkQueue作为WorkerQueue
JDK 1.8 newWorkStealingPool
实现用到了ForkJoinPool,用到了分而治之,递归计算的算法
自定义创建线程池
corePoolSize
情况
CPU密集型
耗时IO型
计算公式
线程数 = CPU核心数 *( 1+平均等待时间/平均工作时间 )
停止线程池
shutdown方法
shutdown方法是关闭线程池
执行完这个方法后,线程池不一定会立即停止
比如,线程池在执行到一半时,线程中有正在执行的任务,队列中也可能有等待被执行的任务;所以,不是我们调用shutdown方法后,整个线程池就能停的
在我们调用了shutdown方法后,线程池就知道了【我们想要停止线程池的意图】;
这个时候,为了安全起见,线程池会把正在执行的任务及队列中等待执行的任务都执行完毕后,再去关闭;
这个时候,为了安全起见,线程池会把正在执行的任务及队列中等待执行的任务都执行完毕后,再去关闭;
调用了shutdown方法后,如果还有新的任务过来,线程池就会拒绝;
拒绝策略
AbortPolicy
直接丢弃任务,抛出异常,这是默认策略
DiscardPolicy
直接丢弃任务,也不抛出异常
CallerRunsPolicy
只⽤调⽤者所在的线程来处理任务
DiscardOldestPolicy
丢弃等待队列中最旧的任务,并执⾏当前任务
线程池钩子方法
beforeExecute()
线程池执行某个任务前会调用
afterExecute()
任务结束后(任务异常退出)会执行
terminated()
线程池执行结束后执行
实现的线程复用
线程池有哪些状态
RUNNING
运行状态,线程池创建好之后就会进入此状态,如果不手动调用关闭方法,那么线程池在整个程序运行期间都是此状态。
SHUTDOWN
关闭状态,不再接受新任务提交,但是会将已保存在任务队列中的任务处理完。
STOP
停止状态,不再接受新任务提交,并且会中断当前正在执行的任务、放弃任务队列中已有的任务。
TIDYING
整理状态,所有的任务都执行完毕后(也包括任务队列中的任务执行完),当前线程池中的活动线程数降为 0 时的状态。到此状态之后,会调用线程池的 terminated() 方法。
TERMINATED
销毁状态,当执行完线程池的 terminated() 方法之后就会变为此状态。
线程池的注意点
避免任务堆积
避免线程数增加
排查线程泄露
0 条评论
下一页