Java线程池的原理
Java线程池的原理
线程池是一种池化技术,用于创建和管理线程,避免频繁的创建和销毁,提高性能和响应速度。
Java线程池有几个核心参数
1、核心线程数
2、最大线程数
3、工作队列
4、最大空闲时间
5、拒绝策略
主要工作原理如下
1、默认情况下是不会创建线程的,只有当任务提交也就是执行了submit方法之后才会创建线程
2、当核心线程数满了之后,也不会新建线程,而是把任务堆积在工作队列中
3、当核心线程满了,并且工作队列也满了才会创建新线程
4、当核心线程满了,并且超过最大线程数的时候就会采取拒绝策略
5、当线程运行一段时间,存在空闲线程的时候,如果空闲线程超过最大空闲时间就会销毁线程,直到线程数等于核心线程数才停止销毁。
通常会使用自定义线程池,一般通过java.util.concurrent.ThreadPoolExecutor构造函数
1 | public ThreadPoolExecutor( |
Java并发库中的线程池有哪些?他们有什么区别
Java并发库中提供了几种常见的线程池,主要是用Excutor工具类来创建的。
1、FixedThreadPool 创建一个固定线程数的线程池
线程池中的线程数是固定的,如果有空闲线程会被复用,如果线程都在忙,就会放到工作队列中。
这个适合负载稳定的场景,任务量确定不需要动态创建线程的场景。
2、CachedThreadPool 一个根据需要动态创建线程的线程池
这个线程池没有线程数量的上限, 空闲线程60秒会被回收,如果有新任务且没有可用的线程会直接创建新线程
适用短时间内大量并发请求的环境,线程变化很大的环境
3、SingleThreadExcutor 创建只有一个线程的线程池
只有一个线程处理任务,按照任务提交的顺序执行
适合需要保证任务顺序执行,并且不需要并发需求的场景
4、ScheduledThreadPool 支持定时任务和周期性任务的线程池
可以定时或者以固定频率执行任务,线程池大小可以由用户自己定义
适合需要周期性执行任务的场景,如定时任务调度器
5、WorkStealingPool 基于任务窃取算法的线程池
每个线程都会维护一个双端队列deque,线程可以从自己的队列中取任务执行,如果线程任务都执行完,可以从其他线程中的队列中 窃取任务执行,达到负载均衡的效果
适合大量小任务并发执行,特别是递归算法或者大任务分解成小任务的场景。
Java线程池有哪些拒绝策略
一共提供了4种
1、AbortPolicy 当任务队列满且没有线程空闲,此时添加任务会直接抛出异常,这也是默认的拒绝策略。适用于必须通知调用者任务未能被执行的场景。
2、CallerRunsPolicy 当任务队列满且没有线程空闲,此时添加任务由调用者线程执行,适用于希望减缓任务提交速度来稳定系统的场景。
3、DiscartOldestPolicy 当任务队列满且没有空闲线程,会删除最早的任务,然后重新提交当前任务,适用于希望丢弃最旧的任务以保证新的重要人物能够被处理的场景。
4、DiscardPolicy ,直接丢弃当前提交的任务,不会执行任何操作,也不会抛出异常。适用于对部分人物丢弃没有影响的场景,或系统负载较高时不需要处理所有任务的场景。
可以实现RejectedExecutionHandler 接口来定义 自定义的拒绝策略,例如记录日志或者任务重新排队。
为什么线程池要使用阻塞队列,而不是直接增加线程
因为没创建一个线程都会占用一定的系统资源,如栈空间,线程调度开销等,直接增加线程会迅速消耗系统资源,导致性能下降。
使用阻塞队列可以将任务暂存,避免线程数量无限增长,确保资源利用率更高。
如果阻塞队列满了,说明此时系统负载很大,再去增加线程到最大线程数去消化任务即可。