java 线程池

本文详细介绍了Java线程池的使用原因、参数配置、任务拒绝策略、线程池状态及其转换,并讨论了线程池中线程复用、阻塞队列的作用以及不同类型的阻塞队列。此外,还分析了Executors提供的四种线程池及其适用场景,最后给出了线程池的合理配置建议。
摘要由CSDN通过智能技术生成


为什么用线程池?
当资源的数量不够用的时候,可以采用 池化技术,如线程池,数据库连接池
复用线程,减少创建销毁线程的资源消耗,提升性能
提高响应速度,有任务时不用等线程创建就能立即执行
方便管理,统一调度调优监控
----------------------------------------
线程池参数
corePoolSize 核心线程数,默认线程空闲也不会回收
maxinumPoolSize 最大线程数,当核心线程数不够用时,就创建临时线程,但线程池里的线程总数不能超过最大线程数
keepAliveTime 线程空闲存活时间
workQueue 任务队列
threadFactory 生产线程的工厂,可以使用默认的,或自定义线程工厂
rejectedExecutionHandler 任务拒绝策略
----------------------------------------
拒绝任务的两种情况
1.线程池已经调用了 shutdown 等方法关闭了
2.最大线程数已满
----------------------------------------
任务拒绝策略
AbortPolicy 拒绝策略
线程池默认策略,拒绝新任务,同时抛异常 RejectedExecutionException
DiscardPolicy 抛弃策略,丢弃任务
DiscardOldestPolicy 抛弃最老任务策略
抛弃队头任务,再入队
CallerRunsPolicy 调用者执行策略
用提交任务的线程执行任务
自定义策略
----------------------------------------
线程池的5种状态
-----------------------------
running 
线程池创建以后的初始状态,
正常处理任务
-----------------------------
shutdown 
调用了 shutdown() 后,状态从 running 变为 shutdown
不再接收新任务,会将任务队列中的任务执行完
-----------------------------
stop 
调用了 shutdownnow() 后,状态从 running/shutdown 变为 stop
将会终止工作线程,清空任务队列
-----------------------------
tidying 
所有工作线程已停止,工作队列清空以后,状态从 stop 变为 tidying
将会执行 terminated() 钩子方法
-----------------------------
terminated 
执行完 terminated() 后,状态从 tidying 变为 terminated
----------------------------------------
线程池任务调度流程
线程池添加任务
如果核心线程数未满,就创建核心线程执行任务
如果核心线程数已满,任务队列未满,将任务放入任务队列中
如果任务队列已满,未达到最大线程数,创建临时线程执行,临时线程忙完之后,达到空闲存活时间就回收
如果达到最大线程数,拒绝处理
----------------------------------------
线程池中的线程复用原理
线程池里的线程会不断的从任务队列中获取任务来执行,执行一个任务时调用任务的 run() 方法,然后又执行下一个任务调用任务的 run() 方法,如此循环,直到空闲
----------------------------------------
线程池中阻塞队列的作用?
接收任务,没有任务时挂起获取任务的线程,有任务时唤醒挂起的线程
----------------------------------------
BlockingQueue
---------------------
boolean offer(E e);
往 BlockingQueue 里加入数据, 成功返回 true, 失败返回 false
---------------------
boolean offer(E e, long timeout, TimeUnit unit)
        throws InterruptedException;
如果在指定的时间内,不能往队列中加入数据,则返回失败
---------------------
void put(E e) throws InterruptedException;
往 BlockingQueue 里加入数据, 如果 BlockQueue 满了, 阻塞调用该方法的线程,
直到 BlockingQueue 里面有空间再唤醒
---------------------
E poll(long timeout, TimeUnit unit)
    throws InterruptedException;
从 BlockingQueue 取出一个队首的对象,在指定时间内没有数据可取,返回失败
---------------------
E take() throws InterruptedException;
取走 lockingQueue 里排在首位的对象, 若BlockingQueue为空, 阻塞进入等待状态,
直到 BlockingQueue 有新的数据被加入
---------------------
LinkedBlockingQueue
链表实现的阻塞队列,按FIFO排序任务
适合并发程度 高 的情况下使用
---------------------
ArrayBlockingQueue
数组实现的有界队列,创建时设置大小,按FIFO排序任务
适合并发程度 低 的情况下使用
---------------------
DelayQueue - 无界阻塞延迟队列
队列中每个元素都有过期时间,只有过期的元素才能出队
底层是 PriorityBlockingQueue,对头的元素是过期最快的元素
---------------------
SynchronousQueue
同步队列,不存储元素的阻塞队列,插入元素的线程必须等到另一个线程移除操作,否则插入操作一直阻塞
适合生产者处理能力和消费者处理能力相差不大的情况下使用
----------------------------------------
Executors 提供四种线程池
newSingleThreadExecutor 单线程线程池
一个线程一个阻塞队列,
适合多个任务按顺序执行的场景
无界队列(LinkedBlockingQueue)如果任务提交速度长期大于任务处理速度会导致队列堆积大量任务内存溢出

newFixedThreadPool 定长线程池
提交任务时,
线程数没有达到固定数量,就创建一个新线程
达到固定数量就保持不变,如果某个线程执行异常而结束,线程池会补充一个新线程
如果没有空闲线程,新任务会进入阻塞队列
适合长期稳定的任务,可通过固定线程数防止 cpu 被长时间过度消耗
无界队列(LinkedBlockingQueue)如果任务提交速度长期大于任务处理速度会导致队列堆积大量任务内存溢出

newCachedThreadPool 可缓存线程池
提交任务时,没有空闲线程,就创建一个
及时回收空闲线程
适合处理突发性强耗时较短的任务场景
SynchronousQueue 同步队列
最大线程数无穷大,大量任务会产生大量的线程导致内存溢出或耗尽cpu

newScheduledThreadPool 可调度线程池,支持延时及周期性任务执行
DelayQueue - 无界阻塞延迟队列
最大线程数无穷大,大量任务会产生大量的线程导致内存溢出或耗尽cpu

大厂不允许使用 Executors 创建线程池,要求使用标准构造器 ThreadPoolExecutor 创建线程池
线程数配置

公用配置
corePoolSize 和 maxinumPoolSize 保持一致,有新任务时没有空闲线程就创建新线程,而不是放在队列里等线程空闲
使用有界队列,根据具体情况配长度,以测试为准
LinkedBlockingQueue(128)
keepAliveTime 30s
allowCoreThreadTimeOut(true)

IO 密集型任务
为提高 cpu 利用率,线程数配 cpu 核心数的2倍

CPU 密集型任务
线程数等于CPU核心数,减少切换线程消耗时间

混合型任务
最佳线程数 = ((线程等待时间 + 线程CPU时间)/ 线程CPU时间) * CPU核心数

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

叫我三师弟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值