java线程池
构造方法
从ThreadPoolExecutor的构造方法入手
1 |
|
3 个最重要的参数:
corePoolSize : 核心线程数,定义了最小可以同时运行的线程数量。
maximumPoolSize : 线程池允许同时运行的最大线程数。当队列中存放的任务达到队列容量的时候,当前可以同时运行的线程数量变为最大线程数。
workQueue: 当新任务来的时候会先判断当前运行的线程数量是否达到核心线程数,如果达到的话,就会被存放在队列中。
常见参数:
keepAliveTime:当线程池中的线程数量大于 corePoolSize 的时候,如果这时没有新的任务提交,核心线程外的线程不会立即销毁,而是会等待,直到等待的时间超过了 keepAliveTime才会被回收销毁;
unit : keepAliveTime 参数的时间单位。
threadFactory :executor 创建新线程的时候会用到。
handler :饱和策略。
饱和策略
ThreadPoolExecutor.AbortPolicy: 拒绝请求,同时抛出RejectedExecutionException
。默认为此策略。
ThreadPoolExecutor.CallerRunsPolicy: 直接在execute
方法中运行新任务
ThreadPoolExecutor.DiscardOldestPolicy: 丢掉最早未执行的任务
ThreadPoolExecutor.DiscardPolicy: 直接丢掉新任务
使用示例
1 |
|
1 |
|
当前线程池配置:
corePoolSize = 2
maximumPoolSize = 10
workQueue 大小 =5
当启动7个线程的时候:
1
2
3
4
5
6
7activeCount = 2
thread name:pool-1-thread-2 | 2 running 17:27:35.362
thread name:pool-1-thread-1 | 1 running 17:27:35.362
thread name:pool-1-thread-2 | 4 running 17:27:45.362
thread name:pool-1-thread-1 | 3 running 17:27:45.362
thread name:pool-1-thread-2 | 5 running 17:27:55.374
thread name:pool-1-thread-1 | 6 running 17:27:55.374可以看出,线程池每次会同时执行2个任务,并没有按最大线程数10来执行,原因是什么呢?
我们把线程数调到8个再看下:
1
2
3
4
5
6
7activeCount = 3
thread name:pool-1-thread-3 | 8 running 17:28:44.389
thread name:pool-1-thread-1 | 1 running 17:28:44.389
thread name:pool-1-thread-2 | 2 running 17:28:44.389
thread name:pool-1-thread-1 | 3 running 17:28:54.392
thread name:pool-1-thread-3 | 4 running 17:28:54.392
thread name:pool-1-thread-2 | 5 running 17:28:54.392这个就和workQueue有关系了,当workQueue没有满的时候,线程池的最大线程数=corePoolSize,当workQueue被提交满的时候,maximumPoolSize就生效了,最大线程数=maximumPoolSize。
当前情况下,第7个任务提交后,线程池活跃线程=corePoolSize=2,队列为5,刚好填满队列,当第8个任务提交的时候,线程池就开辟一个新线程,来执行任务8了。再把线程数调到16个再看下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task com.wekri.abroad.T@2077d4de rejected from java.util.concurrent.ThreadPoolExecutor@7591083d[Running, pool size = 10, active threads = 10, queued tasks = 5, completed tasks = 0]
at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2047)
at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:823)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1369)
at com.wekri.abroad.Tests.main(Tests.java:22)
thread name:pool-1-thread-3 | 8 running 17:32:59.186
thread name:pool-1-thread-10 | 15 running 17:32:59.186
thread name:pool-1-thread-8 | 13 running 17:32:59.187
thread name:pool-1-thread-6 | 11 running 17:32:59.188
thread name:pool-1-thread-2 | 2 running 17:32:59.187
thread name:pool-1-thread-1 | 1 running 17:32:59.188
thread name:pool-1-thread-9 | 14 running 17:32:59.189
thread name:pool-1-thread-5 | 10 running 17:32:59.186
thread name:pool-1-thread-4 | 9 running 17:32:59.189
thread name:pool-1-thread-7 | 12 running 17:32:59.187当前情况下,第15个任务提交的后,线程池活跃线程=maximumPoolSize=10,队列为5,刚好填满队列,当第16个任务提交的时候,就按照饱和策略处理第16个任务了。
总结:当线程池中的活跃线程到达maximumPoolSize的时候,并且workQueue满了,就开始使用饱和策略了。
分析
我们看下源码中的execute
方法:
1 |
|
通过下图可以更好的对上面这 3 步做一个展示(来源:互联网)
生命周期
状态 | 描述 |
---|---|
RUNNING | 接受新任务并处理排队的任务 |
SHUTDOWN | 不接受新任务,但是处理排队的任务 |
STOP | 不接受新任务,不处理排队的任务,并中断正在进行的任务 |
TIDYING | 所有任务已终止,workerCount为零,线程过渡到状态TIDYING将运行terminated()方法 |
TERMINATED | terminated() 方法执行完成 |