说明
线程池有大小,当线程池不够承载时,就涉及到拒绝策略,有预定的策略,也可以自定义
拒绝处理的时机
当线程数量达到
maxPoolSize,且队列已经满了, 会采取拒绝策略当线程池调用
shutdown()的时候, 会等待线程池的任务执行完毕, 再关闭线程池, 关闭线程池之前, 采取拒绝策略shutdownNow(), 会立刻关闭, 并且停止执行任务. 并采取拒绝策略
拒绝策略分类
AbortPolicy:默认策略CallerRunsPolicyDiscardPolicyDiscardOldestPolicy- 实现
RejectedExecutionHandler接口,可自定义策略
AbortPolicy 中止策略(推荐)
功能:当触发拒绝策略时,直接抛出拒绝执行的异常,中止策略的意思也就是打断当前执行流程
默认策略
使用场景:适用一般场景
注意:要正确处理抛出的异常,会打断当前的执行流程
推荐使用该策略,中止后,由程序员处理
源码
public static class AbortPolicy implements RejectedExecutionHandler {
public AbortPolicy() { }
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
throw new RejectedExecutionException("Task " + r.toString() +
" rejected from " +
e.toString());
}
}
例子
由于 corePoolSize、maximumPoolSize 是 1,也就是只能有 1 个线程运行
由于队列大小是 1,只能放 1 个线程
默认使用 AbortPolicy 拒绝策略
所以只能添加2个线程,添加第3个线程时,会抛异常
package ThreadPool;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class 拒绝策略_抛异常 {
public static void main(String[] args) {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
1,
1,
10,
TimeUnit.SECONDS,
new LinkedBlockingQueue(1)
);
System.out.println("提交线程1");
threadPoolExecutor.execute(new MyRun("1",threadPoolExecutor));
System.out.println("提交线程2");
threadPoolExecutor.execute(new MyRun("2",threadPoolExecutor));
System.out.println("提交线程3");
try {
/*
由于 corePoolSize、maximumPoolSize是1,队列大小是1
也就是只能有1个线程运行,队列只能放1个线程,
默认使用 AbortPolicy 拒绝策略
所以添加第3个线程时,会抛异常
*/
threadPoolExecutor.execute(new MyRun("3", threadPoolExecutor));
}catch (Exception e){
System.out.println("拒绝策略,抛出异常:"+e );
}
// 关闭线程池
threadPoolExecutor.shutdown();
}
static class MyRun implements Runnable {
String name;
ThreadPoolExecutor threadPoolExecutor;
public MyRun(String name, ThreadPoolExecutor threadPoolExecutor) {
this.name = name;
this.threadPoolExecutor = threadPoolExecutor;
}
@Override
public void run() {
System.out.println("----"+name+" 线程开始");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("===="+name+" 线程结束");
}
}
}
执行结果如下:
CallerRunsPolicy 策略
当触发拒绝策略时,只要线程池没有关闭,就由提交任务的当前线程处理。
使用场景:一般在不允许失败的、对性能要求不高、并发量较小的场景下使用,因为线程池一般情况下不会关闭,也就是提交的任务一定会被运行,但是由于是调用者线程自己执行的,当多次提交任务时,就会 阻塞后续任务执行,性能和效率自然就慢了。
源码
public static class CallerRunsPolicy implements RejectedExecutionHandler {
public CallerRunsPolicy() { }
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
r.run();
}
}
}
例子
package ThreadPool;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class 拒绝策略_CallerRunsPolicy {
public static void main(String[] args) {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
1,
1,
10,
TimeUnit.SECONDS,
new LinkedBlockingQueue(1),
new ThreadPoolExecutor.CallerRunsPolicy()
);
System.out.println("提交任务1");
threadPoolExecutor.execute(new MyRun("1"));
System.out.println("提交任务2");
threadPoolExecutor.execute(new MyRun("2"));
System.out.println("提交任务3");
threadPoolExecutor.execute(new MyRun("3"));
System.out.println("执行的末尾");
}
static class MyRun implements Runnable {
String name;
public MyRun(String name) {
this.name = name;
}
@Override
public void run() {
System.out.println("----"+name+" 任务开始");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("===="+name+" 任务结束");
}
}
}
执行结果:
DiscardPolicy 丢弃策略
功能:丢弃这个任务,不触发任何动作
使用场景:如果提交的任务无关紧要,就可以使用该策略 。一般不用
源码
public static class DiscardPolicy implements RejectedExecutionHandler {
public DiscardPolicy() { }
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
}
}
DiscardOldestPolicy 弃老策略
功能:如果线程池未关闭,就弹出队列头部的元素,然后尝试执行
使用场景:这个策略还是会丢弃任务,丢弃时也是毫无声息,但是特点是丢弃的是老的未执行的任务,而且是待执行优先级较高的任务。
源码
public static class DiscardOldestPolicy implements RejectedExecutionHandler {
public DiscardOldestPolicy() { }
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
e.getQueue().poll();
e.execute(r);
}
}
}
参考:
https://segmentfault.com/a/1190000040502271

