java自定义线程池的拒绝策略有几种,分别是什么?

在 Java 中,线程池的拒绝策略用于处理当线程池已满(线程数达最大值且工作队列已满)时新提交的任务。Java 内置了 4 种拒绝策略,均实现了RejectedExecutionHandler接口,同时也支持自定义拒绝策略。以下是详细说明:

1. AbortPolicy(中止策略)

  • 特点:默认拒绝策略,当任务被拒绝时,直接抛出RejectedExecutionException异常,明确告知任务提交失败,阻止系统继续执行。
  • 使用场景:适用于关键任务,需要明确知道任务是否执行成功,不允许任务丢失的场景(如金融交易、数据一致性要求高的操作)。
  • 代码示例
import java.util.concurrent.*;

public class AbortPolicyExample {
    public static void main(String[] args) {
        // 创建线程池:核心线程1,最大线程1,队列容量1
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
            1, 1, 0L, TimeUnit.MILLISECONDS,
            new ArrayBlockingQueue<>(1),
            Executors.defaultThreadFactory(),
            new ThreadPoolExecutor.AbortPolicy() // 指定中止策略
        );

        // 提交3个任务(超过线程池处理能力)
        for (int i = 0; i < 3; i++) {
            final int taskNum = i;
            try {
                executor.submit(() -> {
                    System.out.println("执行任务:" + taskNum);
                    try { Thread.sleep(1000); } catch (InterruptedException e) {}
                });
            } catch (RejectedExecutionException e) {
                System.out.println("任务" + taskNum + "被拒绝:" + e.getMessage());
            }
        }
        executor.shutdown();
    }
}
  • 输出:前两个任务执行,第三个任务抛出异常被拒绝。

2. CallerRunsPolicy(调用者运行策略)

  • 特点:任务被拒绝时,由提交任务的线程(调用者线程)亲自执行该任务,减缓新任务提交速度,给线程池留出处理时间,避免任务丢失。
  • 使用场景:适用于任务提交频率不高,且不希望任务丢失的场景(如非核心但需要执行的后台任务,避免系统过载)。
  • 代码示例
import java.util.concurrent.*;

public class CallerRunsPolicyExample {
    public static void main(String[] args) {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
            1, 1, 0L, TimeUnit.MILLISECONDS,
            new ArrayBlockingQueue<>(1),
            Executors.defaultThreadFactory(),
            new ThreadPoolExecutor.CallerRunsPolicy() // 指定调用者运行策略
        );

        for (int i = 0; i < 3; i++) {
            final int taskNum = i;
            executor.submit(() -> {
                System.out.println("执行任务" + taskNum + ",执行线程:" + Thread.currentThread().getName());
                try { Thread.sleep(1000); } catch (InterruptedException e) {}
            });
        }
        executor.shutdown();
    }
}
  • 输出:前两个任务由线程池线程执行,第三个任务由主线程(main)执行(调用者线程)。

3. DiscardPolicy(丢弃策略)

  • 特点:任务被拒绝时,直接丢弃该任务,不做任何处理,也不抛出异常,任务无声消失。
  • 使用场景:适用于非关键任务,任务丢失不影响系统核心功能(如日志收集、统计上报等可容忍少量数据丢失的场景)。
  • 代码示例
import java.util.concurrent.*;

public class DiscardPolicyExample {
    public static void main(String[] args) {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
            1, 1, 0L, TimeUnit.MILLISECONDS,
            new ArrayBlockingQueue<>(1),
            Executors.defaultThreadFactory(),
            new ThreadPoolExecutor.DiscardPolicy() // 指定丢弃策略
        );

        for (int i = 0; i < 3; i++) {
            final int taskNum = i;
            executor.submit(() -> {
                System.out.println("执行任务:" + taskNum);
                try { Thread.sleep(1000); } catch (InterruptedException e) {}
            });
        }
        executor.shutdown();
    }
}
  • 输出:仅前两个任务执行,第三个任务被直接丢弃,无任何提示。

4. DiscardOldestPolicy(丢弃最旧任务策略)

  • 特点:任务被拒绝时,丢弃工作队列中最旧的任务(队列头部的任务),然后尝试将新任务加入队列。
  • 使用场景:适用于希望新任务优先执行,且旧任务可被替代的场景(如实时数据处理,新数据比旧数据更有价值)。
  • 代码示例
import java.util.concurrent.*;

public class DiscardOldestPolicyExample {
    public static void main(String[] args) {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
            1, 1, 0L, TimeUnit.MILLISECONDS,
            new ArrayBlockingQueue<>(1),
            Executors.defaultThreadFactory(),
            new ThreadPoolExecutor.DiscardOldestPolicy() // 指定丢弃最旧任务策略
        );

        for (int i = 0; i < 3; i++) {
            final int taskNum = i;
            executor.submit(() -> {
                System.out.println("执行任务:" + taskNum);
                try { Thread.sleep(1000); } catch (InterruptedException e) {}
            });
        }
        executor.shutdown();
    }
}
  • 输出:任务 0 执行,任务 1 被放入队列,任务 2 提交时触发策略:丢弃队列中最旧的任务 1,将任务 2 加入队列,最终执行任务 0 和任务 2。

5. 自定义拒绝策略

  • 特点:通过实现RejectedExecutionHandler接口,自定义任务被拒绝时的处理逻辑(如记录日志、持久化任务到数据库、重试等)。
  • 使用场景:适用于业务复杂的场景(如任务必须执行,需保存到本地文件或消息队列,后续重试)。
  • 代码示例
import java.util.concurrent.*;

// 自定义拒绝策略:记录日志并保存任务
class CustomRejectPolicy implements RejectedExecutionHandler {
    @Override
    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
        System.out.println("任务" + r.toString() + "被拒绝,已记录日志并保存到数据库");
        // 实际场景中可添加:保存任务到数据库/消息队列,后续重试
    }
}

public class CustomPolicyExample {
    public static void main(String[] args) {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
            1, 1, 0L, TimeUnit.MILLISECONDS,
            new ArrayBlockingQueue<>(1),
            Executors.defaultThreadFactory(),
            new CustomRejectPolicy() // 使用自定义策略
        );

        for (int i = 0; i < 3; i++) {
            final int taskNum = i;
            executor.submit(() -> {
                System.out.println("执行任务:" + taskNum);
                try { Thread.sleep(1000); } catch (InterruptedException e) {}
            });
        }
        executor.shutdown();
    }
}

  • 输出:前两个任务执行,第三个任务被自定义策略处理(打印日志)。

总结

选择拒绝策略时需根据业务对任务的重要性、容忍丢失程度、系统负载等因素决定。内置策略适用于简单场景,复杂场景可通过自定义策略灵活处理。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值