美文网首页
ThreadPoolExecutor使用与注意事项

ThreadPoolExecutor使用与注意事项

作者: perseverance_li | 来源:发表于2020-06-11 15:29 被阅读0次

为什么用线程池

线程池的主要特点有:线程复用、控制最大并发数、线程管理
使用线程池主要目的:
1.降低资源消耗。通过重复利用已经创建的线程降低线程创建和销毁造成的消耗
2.提高响应速度。任务到达时,任务可以不需要等到线程创建就能立即执行。
3.提高线程的可管理性。线程资源如果无限创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可进行统一的分配,调优和监控

结构图

类图关系

线程池如何使用

使用线程池工具类创建Executors,常用的线程池有
Executors.newFixedThreadPool(xx)
Executors.newSingleThreadExecutor(xx)
Executors.newCachedThreadPool(xx)
根据需求自定义线程池:


构造方法

线程池的主要参数

参数名 类型 说明
corePoolSize int 线程池中常驻核心线程数
maximumPoolSize int 线程池能够容纳同时执行的最大线程数,此值必须大于等于1(corePoolSize 和 workQueue满了之后线程池扩容的最大值)
keepAliveTime long 多余的空闲线程存活时间,当前线程池线程数量超过corePoolSize时,当空闲时间达到keepAliveTime值时,多余空闲线程会被销毁直到只剩下corePoolSize个线程为止
unit TimeUnit keepAliveTime的单位
workQueue BlockingQueue<Runnable> 任务队列,被提交但尚未被执行的任务
threadFactory ThreadFactory 表示生产线程池中工作线程的线程工厂,用于创建线程一般默认即可
handler RejectedExecutionHandler 拒绝策略,表示队列满了并且工作线程大于等于线程池的最大线程数(maximumPoolSize)之后在提交的线程的拒绝策略

工作流程

线程池工作流程
线程池工作流程

主线程调用execute()方法添加一个任务时,线程池会有如下逻辑:
1.如果正在运行的线程数量<corePoolSize,马上创建线程运行这个任务
2.如果正在运行的线程数量>=corePoolSize,那么将这个任务放入队列
3.如果队列满了且正在运行的线程数量<maximumPoolSize,创建非核心线程立刻运行这个任务
4.如果队列满了且正在运行的线程数量>=maximumPoolSize,线程池会启动饱和拒绝策略来执行

拒绝策略

策略 介绍
AbortPolicy 默认策略,触发时直接抛出RejectedExecutionException异常阻止系统正常运行
CallerRunsPolicy “调用者运行”一种调节机制,该策略既不会抛弃任务,也不会抛出异常,而是将任务返回到调用者运行
DiscardPolicy 直接丢弃任务,不做任何处理,也不抛出异常。如果任务运行丢弃,这是最好的方案
DiscardOldestPolicy 抛弃队列中等待最久的任务,然后把当前任务加入队列尝试再次提交当前任务
自定义策略 实现RejectedExecutionHandler接口自定义拒绝策略,入将任务放入数据库、提交到redis等,当线程池空闲时读取数据库、redis中的任务执行

合理配置线程数

1.corePoolSize可以无所谓最小可以设置为0
2.maximumPoolSize
   CPU密集型 核心数+1
   IO密集型:任务需要大量的io,即大量的阻塞
     1)CPU核心数*2
     2) cpu核数 / 1-阻塞系数 阻塞系数0.8~0.9之间 例子:8核cpu 8 / 1-0.9 = 80
   这两种可根据实际情况测试对比后设置

使用时其它注意事项

摘自阿里巴巴Java开发手册(泰山版)

相关文章

网友评论

      本文标题:ThreadPoolExecutor使用与注意事项

      本文链接:https://www.haomeiwen.com/subject/czpbtktx.html