需要的时候可以快速使用,不用重新收集
| 参数名 | 类型 | 含义 |
|---|---|---|
| corePoolSize | int | 核心线程数 |
| maxPoolSize | int | 最大线程数 |
| keepAliveTime | long | 保持存活时间 |
| workQueue | BlockingQueue | 任务存储队列 |
| threadFactory | ThreadFactory | 当线程池需要新的线程时,会使用ThreadFactory来生成新的线程 |
| Handler | RejectedExecutionHandler | 由于线程池无法接受你提交的任务的拒绝策略 |
(1)corePoolSize指的是核心线程数:线程池在完成初始化后,默认情况下,线程池中并没有任何线程,线程池会等待有任务到来时,再创建新线程去执行任务
(2)最大量maxPoolSize:在核心线程数的基础上,额外增加的线程数的上限
(3)添加线程规则:
(4)增减线程的特点
如果线程池当前的线程数多于corePoolSize,那么如果多于的线程空闲时间超过keepAliveTime,它们就会被终止
有3种最常见的队列类型
直接交换:SynchronousQueue
无界队列:LinkedBlockingQueue
有界队列:ArrayBlockingQueue
守护线程和普通线程(也成为用户线程)的区别主要在于是否影响jvm的结束。具体而言,如果普通线程没有结束运行的话,jvm也是不会停止运行的,但是假设所有的用户线程都已经结束了,而只剩下守护线程,那么jvm便会认为此时没有继续运行的必要,从而停止。
非常典型的守护线程就是我们的垃圾处理器,也就是GC。
在平时的学习和工作中,是否需要去把线程设置为守护线程呢?
答案是,通常情况下没有必要,因为我们假设把线程设置为守护线程,那么一旦其他的线程都已终止,只剩下这个线程的话,无论这个线程正在执行什么任务,它都会被停止。假设我们正在读取文件,那么可能会造成数据只读到一般的情况,或者是其他各种各样的问题。
所以在平时的学习工作中,我们只需要去创建普通的线程就可以了,对于守护线程,只需要了解它的概念和特点。
CPU密集型(加密、计算hash等):最佳线程数为CPU核心数的1-2倍
耗时IO型(读写数据库、文件、网络读写等):最佳线程数一般会大于CPU核心数很多倍
参考Brain Goetz推荐的计算方法:
线程数 = CPU核心数*(1 + 平均等待时间/平均工作时间)
FixedThreadPool
核心线程池和最大线程数相同,队列满后,无法再增加线程
CachedThreadPool
具有自动回收多余线程的功能,队列没有容量,线程数可以很多
ScheduledThreadPool
支持定时及周期性任务执行的线程池
SingleThreadExecutor
只会用唯一的工作线程来执行任务(用到的场景并不多)
1、shutdown
运行这个方法之后并不一定会停止,事实上,这个方法仅仅是初始化整个关闭过程。运行这个方法,会把正在执行的和队列中等待的都执行完毕之后再关闭,但是不会再增加任务。
2、isShutdown
3、isTerminated:线程都结束了返回true
4、awaitTermination
5、shutdownNow
拒绝时机:当Executor关闭时,提交新任务会被拒绝,以及当Executor对最大线程和工作队列容量使用有限边界并且已经饱和时
4种拒绝策略:
线程池、ThreadPoolExecutor、ExecutorService、Executor、Executors等这么多和线程池相关的类,都是什么关系
execute方法:执行任务
| 状态 | 含义 |
|---|---|
| RUNNING | 接受新任务并处理排队任务 |
| SHUTDOWN | 不接受新任务但处理排队任务 |
| STOP | 不接受新任务,也不处理排队任务,并中断正在进行的任务 |
| TIDYING | 所有任务都已终止,workCount为零时,线程会转换到TIDYING状态,并将运行terminate()钩子方法 |
| TERMINATED | terminate()运行完成 |
注:学习来源——慕课网