等待队列也已经满了,再也塞不下新任务了
同时,
线程池中的max线程也达到了,无法继续新任务服务。
这时候我们就需要拒绝策略机制合理的处理这个问题。
AbortPolicy(默认)
以上内置拒绝策略均实现了 RejecteExecutionHandler 接口
答案是一个都不用,我们生产上只能使用自定义的
Executors 中 JDK 已经给你提供了,为什么不用?
设置最大线程数为 5,阻塞队列大小为 3,所以最大线程数是 8。
package com.test.threadpool;
import java.util.concurrent.*;
public class MyThreadPoolDemo {
public static void main(String[] args) {
ExecutorService threadPool = new ThreadPoolExecutor(
2,
5,
1L,
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(3),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
try {
// 模拟10个用户来办理业务,每个用户就是一个来自外部的请求线程
for (int i = 1; i <= 8; i++) {
threadPool.execute(()->{
System.out.println(Thread.currentThread().getName()+"\t 办理业务");
});
// try {TimeUnit.SECONDS.sleep(1);} catch (Exception e) {e.printStackTrace();}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
threadPool.shutdown();
}
}
}
拒绝策略是 AbortPolicy
如果第 9 个请求线程到来时,已经有线程处理完被释放了则可以继续处理第9个线程,反之如果没有释放线程,8个线程都被占用了,就会抛出如下异常:
java.util.concurrent.RejectedExecutionException: Task com.test.threadpool.MyThreadPoolDemo$$Lambda$1/750044075@13a57a3b rejected from java.util.concurrent.ThreadPoolExecutor@b97c004[Running, pool size = 5, active threads = 4, queued tasks = 0, completed tasks = 4]
at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2063)
at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:830)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1379)
at com.test.threadpool.MyThreadPoolDemo.main(MyThreadPoolDemo.java:23)
拒绝策略是 CallerRunsPolicy
当请求线程超过了 8,如果线程池处理不过来,会把任务回退给“调用者”来执行任务,这里的调用者是 main 线程,所以控制台打印结果中包含了“main 办理业务”
pool-1-thread-1 办理业务
pool-1-thread-4 办理业务
main 办理业务
pool-1-thread-3 办理业务
pool-1-thread-3 办理业务
pool-1-thread-3 办理业务
pool-1-thread-2 办理业务
pool-1-thread-4 办理业务
pool-1-thread-1 办理业务
pool-1-thread-5 办理业务
拒绝策略是 DiscardOldestPolicy
丢弃等待最久的任务
拒绝策略是 DiscardPolicy
如果任务数量超出了 “最大线程数” + “阻塞队列容量” 则任务会直接丢弃
CPU密集性的意思是该任务需要大量的运算,而没有阻塞,CPU一直全速运行。
CPU密集任务只有在真正的多核CPU上才能得到加速(通过多线程),
而在单核CPU上,无论你开几个模拟的多线程该任务都不可能得到加速,因为CPU总的运算能力就那些。
CPU密集型任务配置尽可能少的线程数量:
一般公式:CPU核数 + 1 个线程的线程池
通过以下方法可以获取当前服务器的核数。
Runtime.getRuntime().availableProcessors()
需要去数据库读取大量的数据 或 需要经过大量的 IO 操作时,选择使用 IO 密集型。
IO 密集型,即该任务需要大量的 IO,即大量的阻塞。
在单线程上运行 IO 密集型的任务会导致浪费大量的 CPU 运算能力浪费在等待。
所以在 IO 密集型任务中使用多线程可以大大的加速程序运行,即使在单核 CPU 上,这种加速主要就是利用了被浪费掉的阻塞时间。
IO 密集型时,大部分线程都阻塞,故需要多配置线程数:
方案一:
由于 IO 密集型任务线程并不是一直在执行任务,则应配置尽可能多的线程,
如:CPU核数 * 2
方案二
参考公式:
CPU核数 / 1 - 阻塞系数
阻塞系数 在 0.8 ~ 0.9 之间
不如 8 核 CPU:8 / 1 - 0.9 = 80 个线程数