• Java 线程池四种拒绝策略


    jdk1.5版本新增了 JUC 并发包,其中一个包含线程池。

    四种拒绝策略:

    拒绝策略类型 说明
    1 ThreadPoolExecutor.AbortPolicy 默认拒绝策略,拒绝任务并抛出任务
    2 ThreadPoolExecutor.CallerRunsPolicy 使用调用线程直接运行任务
    3 ThreadPoolExecutor.DiscardPolicy 直接拒绝任务,不抛出错误
    4 ThreadPoolExecutor.DiscardOldestPolicy 触发拒绝策略,只要还有任务新增,一直会丢弃阻塞队列的最老的任务,并将新的任务加入

    预先配置

    配置线程池。

    • 核心线程和最大线程都尽量设置的小一点,分别设置成 1 和 2
    • 阻塞队列设置固定长度的有界队列,长度为 1
    • 线程工厂设置默认线程工厂
    // 核心线程数
    int corePoolSize = 1;
    // 最大线程数
    int maximumPoolSize = 2;
    // 线程存活时间
    long keepAliveTime = 10;
    // 线程存活时间单位
    TimeUnit unit = TimeUnit.SECONDS;
    // 有界队列 遵循 FIFO 原则
    BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(1);
    // 线程工厂
    ThreadFactory threadFactory = Executors.defaultThreadFactory();
    
    

    创建线程任务

    创建线程任务,一个线程任务执行一秒:

    class TaskThread implements Runnable{
                    
    		private int i;
    
    		public TaskThread(int i) {
    			this.i = i;
    		}
    
    		@Override
    		public void run() {
    			try {
    				TimeUnit.SECONDS.sleep(2);
    				System.out.println("执行任务:" + i);
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    		}
    	}
    

    拒绝策略一:AbortPolicy

    默认拒绝策略,拒绝任务并抛出任务

    // 拒绝策略 默认拒绝策略,拒绝任务并抛出异常:
    RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();
    ThreadPoolExecutor threadPool = new ThreadPoolExecutor(corePoolSize,
    				maximumPoolSize,
    				keepAliveTime,
    				unit,
    				workQueue,
    				threadFactory,
    				handler);
    		for (int i = 1; i <= 5; i++) {
    			try {
    				threadPool.execute(new TaskThread(i));
    			} catch (Exception e) {
    				System.out.println("【任务" + i + "】报错:" + e.getMessage());
    			}
    
    		}
    
    

    输出

    【任务】4报错:Task com.test.controller.ThreadPoolController$TaskThread@5c0369c4 rejected from java.util.concurrent.ThreadPoolExecutor@50675690[Running, pool size = 2, active threads = 2, queued tasks = 1, completed tasks = 0]
    【任务】5报错:Task com.test.controller.ThreadPoolController$TaskThread@31b7dea0 rejected from java.util.concurrent.ThreadPoolExecutor@50675690[Running, pool size = 2, active threads = 2, queued tasks = 1, completed tasks = 0]
    执行任务:1
    执行任务:3
    执行任务:2
    

    最大线程数 + 阻塞队列 = 3,执行到4,5的时候就抛出错误。这里需要用 try catch 捕获异常。任务1、2、3正常执行。

    如果提交的任务都要执行,可以将抛出的错误任务存入在redis中,然后定时从redis中获取任务,再提交执行。

    拒绝策略二:CallerRunsPolicy

    调用线程运行多余的任务。

    更换拒绝策略,将上面的 AbortPolicy 换成 CallerRunsPolicy

    RejectedExecutionHandler handler = new ThreadPoolExecutor.CallerRunsPolicy();
    

    执行任务,输出:

    执行任务:1
    执行任务:4
    执行任务:3
    执行任务:2
    执行任务:5
    

    最大线程数 + 阻塞队列 = 3,多余的任务还是继续被执行。

    拒绝策略三:DiscardPolicy

    拒绝任务,不会抛出错误。
    更换策略,将CallerRunsPolicy 换成DiscardPolicy:

    RejectedExecutionHandler handler = new ThreadPoolExecutor.DiscardPolicy();
    

    执行任务,输出:

    执行任务:1
    执行任务:3
    执行任务:2
    

    多余的线程任务提交被拒绝,而只执行最大线程数 + 阻塞队列 数量的任务,并且不会抛出错误。

    拒绝策略四:DiscardOldestPolicy

    只要还有任务新增,一直会丢弃阻塞队列的最老的任务,并将新的任务加入到阻塞队列中
    更换策略,将DiscardPolicy 换成DiscardOldestPolicy:

    RejectedExecutionHandler handler3 = new ThreadPoolExecutor.DiscardOldestPolicy();
    

    执行任务,输出:

    执行任务:3
    执行任务:1
    执行任务:5
    

    任务的执行顺序是 核心线程数 —> 阻塞队列 —> 最大线程数,其中任务1,任务3提交成功。

    • 任务2因为在阻塞队列中,
    • 后面的任务4把任务2挤掉,
    • 任务5又把任务4挤掉,所以最后执行的是任务5。

    总结

    本文介绍了线程四种拒绝策略,当工作任务大于最大线程 + 阻塞队列会执行阻塞队列。

    • AbortPolicy 默认策略,拒绝任务,并抛出异常
    • CallerRunsPolicy 调用线程执行对于的任务
    • DiscardPolicy 拒绝任务,不会抛出异常
    • DiscardOldestPolicy 有多余的任务,把阻塞队列最老的任务丢弃,放入新的任务,直到没有新的任务。
      如果觉得文章对你有帮助的话,请点个推荐吧!
  • 相关阅读:
    〖大前端 - 基础入门三大核心之JS篇㊵〗- DOM事件监听及onxxx的使用
    小白一键重装官网下载使用方法
    信息系统项目管理师考点(六十六)计算机信息系统的安全保护等级
    vue-element-admin+springboot登录功能实现
    数据仓库(6)数仓分层设计
    力扣leetcode 850. 矩形面积 II 【困难】
    Transformer模型
    JVM垃圾收集器 从Serial到G1概述
    VMware Workstation 与 Hyper-V 不兼容。请先从系统中移除 Hyper-V 角色
    c语言顺序栈、链栈
  • 原文地址:https://www.cnblogs.com/jeremylai7/p/16197499.html