大家好,又见面了,我是你们的朋友全栈君。
Java提供的策略实现
CallerRunsPolicy
public static class CallerRunsPolicy implements RejectedExecutionHandler {
public CallerRunsPolicy() { }
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
r.run();
}
}
}
CallerRunsPolicy顾名思义就是调用者自己执行,看实现就知道,如果线程池还没有关闭,就让将要被执行的线程自己调用自己的run方法,注意这里不是启动新的线程,只是执行run方法而已。
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());
}
}
AbortPolicy实现非常简单,直接抛出一个RejectedExecutionException异常,ThreadPoolExecutor默认的策略就是这一个。
DiscardPolicy
public static class DiscardPolicy implements RejectedExecutionHandler {
public DiscardPolicy() { }
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
}
}
DiscardPolicy策略就是什么也不做,就是把这一个任务(Runnable)丢弃,这是因为ThreadPoolExecutor在执行拒绝策略的时候就不会新建线程来执行Runnable,也不会加入任务队列了,所以在拒绝策略中什么都不做就是简单的丢弃掉了任务(Runnable)
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);
}
}
}
DiscardOldestPolicy策略不是丢弃提交的任务中最老的,而是丢弃任务队列中队首的任务,然后再次提交新加入的任务。
拒绝策略与模式
从线程池的拒绝策略实现上也体现了面向对象的思想,把拒绝策略抽象在RejectedExecutionHandler接口中,ThreadPoolExecutor关联(更加具体的来说是聚合aggregation)RejectedExecutionHandler接口。
好歹我们也是学过设计模式的,在设计模式中这种模式叫做策略模式(Strategy),虽然实现类的后缀都是Policy但事实上这确实是一个策略模式的应用。对于不同拒绝算法的封装。可以看一下下面的类图。
JDK的源码中有大量的设计模式的使用,有的是非常直接的使用,甚至是为设计模式提供了接口,比如观察着模式。更多的是一些变形的使用,JDK对于设计模式的使用已经到了出神入化,大道无形的地步了。
自定义拒绝策略
既然设计上使用的是策略模式,那么对于我们来说扩展就是相当容易的事情了,简单来一个例子测试一下扩展线程池的策略模式。
import java.math.BigDecimal;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
public class RejectPolicyTest {
private static AtomicInteger discardTaskNum = new AtomicInteger(0);
private static AtomicInteger executeTaskNum = new AtomicInteger(0);
public static void main(String[] args) {
int cpu = Runtime.getRuntime().availableProcessors();
ThreadPoolExecutor pool = new ThreadPoolExecutor(cpu, cpu, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(cpu),
Executors.defaultThreadFactory(), new RejectedExecutionHandler() {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
System.out.println(r + “:is discarded”);
discardTaskNum.incrementAndGet();
}
});
Task task = new Task();
for(int i = 0;i<100;i++){
pool.submit(task);
try {
TimeUnit.MILLISECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
pool.shutdown();
while(!pool.isTerminated());//等待所有的任务执行完成,包括任务队列中的任务
System.out.println(“discardNum:”+discardTaskNum.get());
System.out.println(“executeNum:”+executeTaskNum.get());
}
static class Task implements Runnable {
@Override
public void run() {
System.out.println(“task:” + Thread.currentThread().getName() + “is executing!”);
BigDecimal num1 = new BigDecimal(1.23456);
BigDecimal num2 = new BigDecimal(1.23456);
for (int i = 0; i < 5000000; i++) {//在我的机子上大概运行0.5s
num1.multiply(num2);
}
executeTaskNum.incrementAndGet();
}
}
}
在上面的实例中我们简单的实现了一个匿名的RejectedExecutionHandler,打印一下那些任务被丢弃了,顺便记录了一下被丢弃任务的数量。在上面的例子中的任务是执行5百万次BigDecimal类型的乘法。
总结
Java提供的4中默认策略分别是CallerRunsPolicy如果线程池没有关闭直接当前线程执行run方法,AbortPolicy抛出异常,DiscardPolicy丢弃任务,DiscardOldestPolicy丢弃任务队列头的任务。
Java线程池拒绝策略使用的是策略模式,抽象在RejectedExecutionHandler,如果需要扩展只需要实现RejectedExecutionHandler接口就可以了。
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/147710.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...