当前位置: 首页 > article >正文

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

http://www.kler.cn/a/611697.html

相关文章:

  • Redis的基础,经典,高级问题解答篇
  • ④(上网管理行为-ACG)主备/主主
  • 11:00开始面试,11:08就出来了,问的问题有点变态。。。
  • 零基础使用AI从0到1开发一个微信小程序
  • 十一、JavaScript简单数据类型和复杂数据类型
  • sqlmap 源码阅读与流程分析
  • LeetCode 第36、37题(数独问题)
  • Linux安装Ipanel
  • 反向 SSH 隧道技术实现内网穿透
  • Golang io模块详细功能介绍与示例
  • 数据大屏点亮工业互联网的智慧之眼
  • linux网络编程以及epoll IO多路复用
  • 计算机网络基础:量子通信技术在网络中的应用前景
  • 解决Cubemx生产的 .ioc文件不能外部打开的方法
  • Vulhub靶机--FAll
  • 数据湖的崛起:从大数据到智能未来的钥匙
  • CMake入门及生成windows下的项目示例讲解
  • Postman 请求头详解:快速掌握
  • flutter 获取设备的唯一标识
  • 国产 FPGA 的崛起之路,能否打破 Xilinx 的垄断?