Java 多线程编程之 RejectedExecutionHandler 线程池拒绝策略

RejectedExecutionHandler

public interface RejectedExecutionHandler {

    void rejectedExecution(Runnable r, ThreadPoolExecutor executor);
}
  • RejectedExecutionHandler 是 Java 线程池中用于处理任务被拒绝执行的拒绝处理器接口,当以下情况发生时,会调用拒绝处理器
  1. 线程池已关闭,即线程池调用了 shutdown 方法

  2. 线程池和任务队列都已满(达到最大线程数且队列无空间)

  • Java 提供了 4 种内置的拒绝策略,它们都实现了 RejectedExecutionHandler 接口

一、AbortPolicy

1、基本介绍
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());
    }
}
  1. 默认策略,直接抛出 RejectedExecutionException 异常

  2. 生产环境最常用的策略,强制开发者处理拒绝情况

2、演示
ThreadPoolExecutor executor = new ThreadPoolExecutor(
        2,
        2,
        0,
        TimeUnit.SECONDS,
        new ArrayBlockingQueue<>(2),
        Executors.defaultThreadFactory(),
        new ThreadPoolExecutor.AbortPolicy());

for (int i = 1; i <= 5; i++) {
    int id = i;
    try {
        executor.execute(() -> {
            System.out.println("执行任务 " + id + " 由 " + Thread.currentThread().getName());
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        System.out.println("任务 " + id + " 提交成功");
    } catch (RejectedExecutionException e) {
        System.out.println("任务 " + id + " 被拒绝:" + e.getMessage());
    }
}
  • 输出结果
任务 1 提交成功
任务 2 提交成功
任务 3 提交成功
任务 4 提交成功
执行任务 1 由 pool-1-thread-1
任务 5 被拒绝:Task com.juc.RejectedExecutionHandlerTest$$Lambda$15/0x0000000800c01200@723279cf rejected from java.util.concurrent.ThreadPoolExecutor@10f87f48[Running, pool size = 2, active threads = 2, queued tasks = 2, completed tasks = 0]
执行任务 2 由 pool-1-thread-2
执行任务 3 由 pool-1-thread-1
执行任务 4 由 pool-1-thread-2
  • 输出结果解读
1. 前 4 个任务提交成功(2 个在核心线程执行,2 个在队列中)

2. 第 5 个任务被拒绝,抛出 RejectedExecutionException 异常

二、CallerRunsPolicy

1、基本介绍
public static class CallerRunsPolicy implements RejectedExecutionHandler {

    public CallerRunsPolicy() { }

    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        if (!e.isShutdown()) {
            r.run();
        }
    }
}
  1. 由提交任务的线程直接执行该任务,实现了一种简单的降级策略

  2. 适用于需要保证每个任务都能执行,且可以接受调用线程被用于执行任务的场景

2、演示
ThreadPoolExecutor executor = new ThreadPoolExecutor(
        2,
        2,
        0,
        TimeUnit.SECONDS,
        new ArrayBlockingQueue<>(2),
        Executors.defaultThreadFactory(),
        new ThreadPoolExecutor.CallerRunsPolicy());

for (int i = 1; i <= 5; i++) {
    int id = i;
    executor.execute(() -> {
        System.out.println("执行任务 " + id + " 由 " + Thread.currentThread().getName());
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    });
    System.out.println("任务 " + id + " 提交成功");
}
  • 输出结果
任务 1 提交成功
任务 2 提交成功
任务 3 提交成功
任务 4 提交成功
执行任务 2 由 pool-1-thread-2
执行任务 5 由 main
执行任务 1 由 pool-1-thread-1
任务 5 提交成功
执行任务 4 由 pool-1-thread-1
执行任务 3 由 pool-1-thread-2
  • 输出结果解读
1. 前 4 个任务正常执行

2. 第 5 个任务由主线程执行

三、DiscardPolicy

1、基本介绍
public static class DiscardPolicy implements RejectedExecutionHandler {

    public DiscardPolicy() { }

    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
    }
}
  1. 不抛出异常,也不执行任务,丢弃被拒绝的任务

  2. 适用于可以容忍任务丢失的场景

2、演示
ThreadPoolExecutor executor = new ThreadPoolExecutor(
        2,
        2,
        0,
        TimeUnit.SECONDS,
        new ArrayBlockingQueue<>(2),
        Executors.defaultThreadFactory(),
        new ThreadPoolExecutor.DiscardPolicy());

for (int i = 1; i <= 5; i++) {
    int id = i;
    executor.execute(() -> {
        System.out.println("执行任务 " + id + " 由 " + Thread.currentThread().getName());
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    });
    System.out.println("任务 " + id + " 提交成功");
}
  • 输出结果
任务 1 提交成功
任务 2 提交成功
任务 3 提交成功
任务 4 提交成功
任务 5 提交成功
执行任务 2 由 pool-1-thread-2
执行任务 1 由 pool-1-thread-1
执行任务 3 由 pool-1-thread-1
执行任务 4 由 pool-1-thread-2
  • 输出结果解读
1. 前 4 个任务正常执行

2. 第 5 个任务被丢弃,没有提示或异常

四、DiscardOldestPolicy

1、基本介绍
public static class DiscardOldestPolicy implements RejectedExecutionHandler {

    public DiscardOldestPolicy() { }

    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        if (!e.isShutdown()) {
            e.getQueue().poll();
            e.execute(r);
        }
    }
}
  1. 丢弃队列中最旧的任务(队头的任务)

  2. 适用于新任务比旧任务更重要,且可以接受丢失部分任务的场景

2、演示
ThreadPoolExecutor executor = new ThreadPoolExecutor(
        2,
        2,
        0,
        TimeUnit.SECONDS,
        new ArrayBlockingQueue<>(2),
        Executors.defaultThreadFactory(),
        new ThreadPoolExecutor.DiscardOldestPolicy());

for (int i = 1; i <= 5; i++) {
    int id = i;
    executor.execute(() -> {
        System.out.println("执行任务 " + id + " 由 " + Thread.currentThread().getName());
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    });
    System.out.println("任务 " + id + " 提交成功");
}
  • 输出结果
任务 1 提交成功
任务 2 提交成功
任务 3 提交成功
任务 4 提交成功
任务 5 提交成功
执行任务 1 由 pool-1-thread-1
执行任务 2 由 pool-1-thread-2
执行任务 4 由 pool-1-thread-2
执行任务 5 由 pool-1-thread-1
  • 输出结果解读
1. 前 2 个任务由线程池线程执行,任务 3 和 4 进入队列

2. 当提交任务 5 时,队列中最老的任务 3 被丢弃,任务 5 进入队列

3. 最终执行的任务是 1、2、4、5
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值