Java线程池使用的注意事项
项目中使用的线程池的地方很多,一直以来感觉对它的参数已经掌握的很好了,但是遇到几次问题之后才发现欠缺的这么多遇到的坑
任务提交后长时间没有执行
任务进入了队列,线程还在执行之前的任务。本质原因是对线程和队列的优先级认识不深刻,有一种错觉以为是所有线程都忙的时候才进入任务队列。实际上相反,是队列满的时候才会新建线程(线程数大于core size时)。
线程池中线程执行任务中无故消失(从日志可以看出,任务并未完成,也没有抛出异常)
一般情况下,代码中只会去捕捉回顾线程池重要的配置 线程池参数RuntimeException
,如果抛出Error
则会导致线程退出,而异常信息又没有拿到。最佳的解决办法是给线程池设置UncaughtExceptionHandler
- corePoolSize:核心线程数量
- maximumPoolSize:最大线程数量
- workQueue:等待队列
任务提交时,判断的顺序为 corePoolSize --> workQueue --> maximumPoolSize。这个顺序一定不要弄错了
拒绝策略
RejectedExecutionHandler
- AbortPolicy:直接抛出异常,这是默认策略
- CallerRunsPolicy:用调用者所在的线程来执行任务
- DiscardOldestPolicy:丢弃阻塞队列中靠最前的任务,并执行当前任务
- DiscardPolicy:直接丢弃任务
默认是抛出异常,除非想得特别清楚,不然轻易不要使用其他3种策略内置的四种线程池
- SingleThreadExecutor:单线程化的Executor
- FiexedThreadPool:固定数目线程的线程池(队列数没有限制)
- CachedThreadPool:可缓存的线程池(线程数没有限制)
- ScheduledThreadPool:支持定时及周期性的任务执行的线程池,多数情况下可用来替代Timer类
这4个线程池都可能存在问题,不建议直接使用,建议使用自定义参数的线程池如何优雅地关闭 线程池状态
![Java线程池使用的注意事项](https://img.it610.com/image/info10/be231289e173482f92aeb957f3a90dbd.jpg)
文章图片
线程池状态变换图 上图来自 深入理解Java线程池:ThreadPoolExecutor
- RUNNING:能接受新提交的任务,并且也能处理阻塞队列中的任务;
- SHUTDOWN:关闭状态,不再接受新提交的任务,但却可以继续处理阻塞队列中已保存的任务。
- STOP:不能接受新任务,也不处理队列中的任务,会中断正在处理任务的线程。在线程池处于
RUNNING
或SHUTDOWN
状态时,调用shutdownNow()
方法会使线程池进入到该状态;
- TIDYING:如果所有的任务都已终止了,workerCount (有效线程数) 为0,线程池进入该状态后会调用
terminated()
方法进入TERMINATED
状态。
- TERMINATED:在
terminated()
方法执行完后进入该状态。
// 线程池进入SHUTDOWN状态,停止接受新的任务
executorService.shutdown();
// 等待线程池任务完成
executorService.awaitTermination(30, TimeUnit.SECONDS);
【Java线程池使用的注意事项】在Spring中,如果线程池作为其他Bean中的属性,则需要在Bean的destroy时,关闭线程池
@PreDestroy
public void destroy() {
executorService.shutdown();
executorService.awaitTermination(30, TimeUnit.SECONDS);
}
注意事项
- 线程池使用FutureTask的时候如果拒绝策略设置为了 DiscardPolicy和DiscardOldestPolicy并且在被拒绝的任务的Future对象上调用无参get方法那么调用线程会一直被阻塞。
- 不使用系统自带的四个Executors
- 设置
UncaughtExceptionHandler
- 优雅的关闭线程池
- 深入理解Java线程池:ThreadPoolExecutor
- 线程池的优雅关闭实践
- 线程池使用FutureTask时候需要注意的一点事
- 如何优雅的使用和理解线程池
- Java中线程池,你真的会用吗?
推荐阅读
- JAVA(抽象类与接口的区别&重载与重写&内存泄漏)
- 事件代理
- Java|Java OpenCV图像处理之SIFT角点检测详解
- java中如何实现重建二叉树
- Linux下面如何查看tomcat已经使用多少线程
- 数组常用方法一
- 【Hadoop踩雷】Mac下安装Hadoop3以及Java版本问题
- Java|Java基础——数组
- 多线程NSOperation
- RxJava|RxJava 在Android项目中的使用(一)