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

#详细介绍!!! 线程池的拒绝策略(经典面试题)

本篇单独讲解线程池的拒绝策略,介绍了当线程池任务满了之后,线程池会以什么样的方式来响应添加进来的任务

目录

一:理解线程池拒绝策略的触发情况+代码理解

二:线程池的四种常见的拒绝策略

1.ThreadPoolExecutor.AbortPolicy

2.ThreadPoolExecutor.CallerRunsPolicy

3.ThreadPoolExecutor.DiscardOldestPolicy

4.ThreadPoolExecutor.DiscardPolicy 



一:理解线程池拒绝策略的触发情况+代码理解

当线程池容纳不了任务的时候,则会触发线程池的拒绝策略

线程池能同时容纳的任务数量:最大线程数+任务队列能存储的任务数

看代码理解:

public static void main(String[] args) {
        BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(1);
        ThreadPoolExecutor pool = new ThreadPoolExecutor(1, 2, 10, TimeUnit.SECONDS, queue, new ThreadPoolExecutor.AbortPolicy()) ;

        //此时线程池只有一个核心线程,且队列也只能存储一个任务
        //当我们添加第三个任务时,没地放了,此时会根据最大线程数来新建临时线程执行这个线程,此时创建了一个临时线程执行任务3
        //如果我们再添加任务四:此时最大线程数和存储的队列加起来只能拿到三个任务,那么此时任务四就没地方存储了
        //此时就会触发线程池的拒绝策略
        for (int i = 1; i <= 4; i++) {
            int num = i;
            pool.submit(new Runnable() {
                @Override
                public void run() {
                    while(true){
                        System.out.println("正在执行线程"+num);
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            });
        }
    }

此处创建了一个线程池pool,核心线程数为1,最大线程数为2,任务队列的长度为1

设置线程池的拒绝策略为ThreadPoolExecutor.AbortPolicy

运行结果:

       

详解: 

1.当添加第1个任务进线程池执行的时候,此时线程池直接创建核心线程来执行任务

2.当添加第2个任务进线程池执行的时候,此时还有存储空间,那么第2个任务进去任务队列,等待核心线程执行完毕再弹出任务2进行执行

3.当添加第3个任务进线程池执行的时候,此时核心线程在执行任务1,而任务队列又被任务2给占满了,那么任务3没地方去了,但此时线程数量还没到线程池的最大线程数,这个时候会自动创建临时线程来执行任务3,把任务3给拿走,避免任务3流失

4.当添加第4个任务进线程池执行的时候:此时核心线程数被占用,任务队列和最大线程数都满了,那么此时任务4彻底没地方去了,线程池只能被迫采用拒绝策略来处理当前问题

二:线程池的四种常见的拒绝策略

首先打开官方文档

        可查看到以下四种策略:

1.ThreadPoolExecutor.AbortPolicy

BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(1);
ThreadPoolExecutor pool = new ThreadPoolExecutor(1, 2, 10, TimeUnit.SECONDS, queue, new ThreadPoolExecutor.AbortPolicy()) ;

这种拒绝策略表示:当线程池最大的任务容量已满时,编译器直接抛出异常

上诉代码就是这种情况

通俗理解:

就好像在说,这个问题编译器傻眼了,处理不了,编译器给你一个异常你自己看着办。

2.ThreadPoolExecutor.CallerRunsPolicy

BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(1);
ThreadPoolExecutor pool = new ThreadPoolExecutor(1, 2, 10, TimeUnit.SECONDS, queue, new ThreadPoolExecutor.CallerRunsPolicy()) ;

这种拒绝策略表示:当线程池最大的任务容量已满时,线程池不处理该任务,让添加该任务的线程自己执行

例如前面代码案例如果设置为这个拒绝策略,那么是main线程添加任务4进线程池被拒绝了,此时main线程自己执行任务4

通俗理解:

我把一个任务交给你执行,你自己也没空闲时间,所以你让我自己去做这个任务

3.ThreadPoolExecutor.DiscardOldestPolicy

BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(1);
ThreadPoolExecutor pool = new ThreadPoolExecutor(1, 2, 10, TimeUnit.SECONDS, queue, new ThreadPoolExecutor.DiscardOldestPolicy) ;

把前面例子改变一下:设置拒绝策略为DiscardOldestPolicy

        并且把代码的死循环改为执行3秒

public static void main(String[] args) throws InterruptedException {
        BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(1);
        ThreadPoolExecutor pool = new ThreadPoolExecutor(1, 2, 10, TimeUnit.SECONDS, queue, new ThreadPoolExecutor.DiscardOldestPolicy()) ;

        //此时线程池只有一个核心线程,且队列也只能存储一个任务
        //当我们添加第三个任务时,没地放了,此时会根据最大线程数来新建临时线程执行这个线程,此时创建了一个临时线程执行任务3
        //如果我们再添加任务四:此时最大线程数和存储的队列加起来只能拿到三个任务,那么此时任务四就没地方存储了
        //此时就会触发线程池的拒绝策略
        for (int i = 1; i <= 4; i++) {
            int num = i;
            pool.submit(new Runnable() {
                @Override
                public void run() {
                    boolean start = true;
                    long time = System.currentTimeMillis();
                    while(start){
                        System.out.println("正在执行线程"+num);
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        if(System.currentTimeMillis() - time >= 3000){
                            start = false;
                        }
                    }

                }
            });
        }
    }

此时代码结果:

 

这种拒绝策略表示:当线程池最大的任务容量已满时,线程池拒绝(删除掉)最老的任务,再把当前任务添加进线池

例如前面代码案例如果设置为这个拒绝策略,那么线程池就把任务队列中最早添加的(最老的)的任务2给删除,再把任务4添加进线程池

通俗理解:

我把任务交你执行,你手底下也有很多任务也没时间做,此时你放下把后续任务中的最早添加的任务给剔除,再把新任务加入后续执行的任务中

4.ThreadPoolExecutor.DiscardPolicy 

BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(1);
ThreadPoolExecutor pool = new ThreadPoolExecutor(1, 2, 10, TimeUnit.SECONDS, queue, new ThreadPoolExecutor.DiscardPolicy ) ;

这种拒绝策略表示:当线程池足底啊的任务容量已满时,线程池拒绝最新添加的任务

 例如前面代码案例如果设置为这个拒绝策略,那么线程池就直接拒绝任务4,不接收任务4

通俗理解:

我把任务交你执行,你手底下也有很多任务也没时间做,此时你直接拒绝这个任务,不做这个任务,那么这个任务就流失了


 

 

 


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

相关文章:

  • 深入理解 SQL 中的 DATEDIFF 函数
  • 粒子群优化 (PSO, Particle Swarm Optimization) 算法详解及案例分析
  • ZooKeeper 核心知识全解析:架构、角色、节点与应用
  • 数据可视化:让数据讲故事的艺术
  • 从玩具到工业控制--51单片机的跨界传奇【3】
  • Eamon.MeituanDotnetSDK 美团C# .Net SDK开源啦
  • 【精彩点评】比特币如何颠覆和改善全球供应链体系并彻底改变行业现状
  • 【SpringBoot】| 邮箱发送验证码,你会了吗?
  • ChatGPT相关核心算法
  • AutoSAR COMM-通信管理器通信通道ID【ComMChannelId】的定义
  • 【lwIP(第四章)】网络接口
  • MYSQL——美团面试题
  • 2023选择网络安全,抓住时代机遇!
  • I.MX6ULL_Linux_驱动篇(32) 设备树GPIO驱动
  • Winform/Csharp中使用Linq的Where条件筛选、Select字段映射(左外连接并设置无匹配时默认值)、OrderBy(排序并自定义排序规则)
  • Excel2010(详细解析)
  • 动态内存函数malloc,calloc,realloc详解
  • 金色传说:SAP-ABAP-SAPLINK 零基础萌新/老鸟通用-SAPLINK最详细使用方式(附:神级SQL编辑器ZTOAD完整导入文件)
  • Web前端:什么是Angular?能做什么?
  • CSDN 编程竞赛四十期题解
  • 【LeetCode】栈和队列练习 4 道题
  • 广度优先寻路算法(一)
  • STM32输出PWM波控制电机转速,红外循迹避障智能车+L298N的详细使用手册、接线方法及工作原理,有代码
  • UniApp + SpringBoot 实现接入支付宝支付功能和退款功能
  • 【面试题系列】K8S面试题(二)
  • Java基础 -- 枚举类Enum