• 07 线程池中的四个任务拒绝策略该用哪一个?


    四个任务拒绝策略该用哪一个?

    在前面的课程中,我们学习了提交任务和取消任务,这一节我们来学习,当提交的任务被拒绝时该怎么办?线程池给我们提供了4个任务拒绝策略,

    也就是4个解决办法,这4个策略分别对应4个类,

    而且他们还以内部类的形式存在于所谓的threadPoolExecutor中。不仅如此,他们还实现了同一个接口rejectExecutionhandler,拒绝执行处理器,

    它里面只有一个方法,rejectedExecution,拒绝任务的代码就写在这个方法里面。

    该方法有两个参数,一个是被拒绝的任务,还有一个是线程池。如果我们想自定义处理器,但还没想好怎么处理被拒绝的任务,那么你可以抛一个拒绝执行异常,接下来我们来依次了解这个词的策略。

     

    首先来看第一个策略,discardPolicy,该策略是直接丢弃任务,

    从源码中我们可以看到 rejectedExecution型方法体是空的,

    什么都没做,等同于将任务丢弃。下面我们来演示该策略。在演示之前我把演示思路说一下,为了限制数量和任务数量可控,我们采用threadPoolExecutor的这种原生方式来创建线程值,线程池中的限制数量为1,

    当我们提交一个任务时,它就会被占满,任务队列大小也是一,

    再提交一个任务时,他也会被沾满。

    如此一来,如果我们再提交任务时,其中已经没有可工作的线程了,

    队列中也没有多余的空位任务,只有被拒绝的命运。 

    按照这个思路我们来编写代码,编写一个runnable波任务task,定一个int类型的属性index,用于给任务编号,这样可以看到哪个任务被执行,哪个任务被拒绝,重载构造的方法用于初始化index,任务内容是输出当前线程名称和任务编号。

    接下来我们来执行该任务,使用ThreadPoolExecutor创建线程值,核心限制数为一,最大限制数也是一,说明线程池中只能存在一个线程,空闲线程存活时间为0,时间单位为秒,说明空闲线程不会被销毁任务,对你采用linkedblockingQueue队列长度为一,说明队列中只能存放一个任务任务,拒绝策略,采用discardPolicy,直接丢弃被拒绝的任务,向线程池中提交三个任务,三个任务的编号分别是123使用try-catch捕获拒绝执行异常。 

    写上finally代码块,在finally代码块中关闭线程池,

    至此main方法编写完成,整个例子也编写完成。执行程序观察执行结果,从执行结果来看,程序输出一二

    说明第三个任务没执行被丢弃了。测试结果符合预期。

    callerRunsPolicy

    看完了第一个策略,再来看下一个策略,callerRunsPolicy。该策略是使用调用者线程直接执行被拒绝的任务。

    从源码中可以看到,当线程池没关闭时,直接调用任务的run方法,而这行代码就是使用调用者的线程执行的,线程池执行任务的途径只有通过execute和submit的方法,所以不会线程池执行的。 

    下面我们来演示该策略还是沿用之前的例子,将策略由discardPolicy改为callerRunsPolicy。例子改写完成

    再来执行程序,看看从执行结果来看,程序输出123,并且三是main线程打印的,

    事实证明被拒绝的任务的确是使用调用者的线程执行的,看完了第二个策略。

    abroadPolicy

    再来看第三个策略,abortPolicy该策略是默认的拒绝策略,

    它的做法是抛出任务拒绝异常。从源码中可以看到方法体中只有一段抛异常的代码,

    下面我们来演示该策略,继续沿用之前的例子,将策略由callerRunsPolicy改为abroadPolicy,因此改写完成,再来执行程序看看。 

     

    从执行结果来看,程序输出1和2,还有拒绝执行异常测试结果符合预期

     discardOldestPolicy

    。接下来我们再来看看最后一个策略,discardOldestPolicy。该策略是丢弃处于任务队列头部的人物,添加被拒绝的任务,

    从源码中可以看到,当线程池没被关闭时,调用任务队列的poll方法,

    该方的作用是移除队列头部元素,也就是移除队列头部任务,然后将被拒绝的任务重新提交给线程池。

    为了演示该策略,我们得改一改之前的任务队列容量,将任务队列容量加一,这样提交的第二个任务就会在队列的头部,第三个任务自然就在第二个任务的后面,此时任务队列被占满,

    在提交任务时会将第二个任务移出队列,第三个任务成为头部任务。 

     第四个任务添加成功,

    按照这个改动来编写代码还是之前的例子。首先将任务队列容量由一改为二,然后将测量由abroadPolicy改为discardOldestPolicy。接着再提交1个任务,一共是提交了4个任务,例子改写完成执行程序看看。

    从执行结果来看,程序输出134,

    果然第二个任务被移出了队列。

    总结

    最后来总结一下本节内容,本节介绍4个任务拒绝策略,它们的作用这里就不再赘述了。在实际开发中abroadPolicy这种策略用的最多,我一般也是用它。当然了你可以制定任务,拒绝策略。 

    附录:

    笔记完整文本:

    在前面的课程中,我们学习了提交任务和取消任务,这一节我们来学习,当提交的任务被拒绝时该怎么办?线程池给我们提供了4个任务拒绝策略,也就是4个解决办法,这4个策略分别对应4个类,而且他们还以内部类的形式存在于所谓的threadPoolExecutor中。不仅如此,他们还实现了同一个接口rejectExecutionhandler,拒绝执行处理器,它里面只有一个方法,rejectedExecution,拒绝任务的代码就写在这个方法里面。该方法有两个参数,一个是被拒绝的任务,还有一个是线程池。如果我们想自定义处理器,但还没想好怎么处理被拒绝的任务,那么你可以抛一个拒绝执行异常,接下来我们来依次了解这个词的策略。 首先来看第一个策略,discardPolicy,该策略是直接丢弃任务,从源码中我们可以看到 rejectedExecution型方法体是空的,什么都没做,等同于将任务丢弃。下面我们来演示该策略。在演示之前我把演示思路说一下,为了限制数量和任务数量可控,我们采用threadPoolExecutor的这种原生方式来创建线程值,线程池中的限制数量唯一,当我们提交一个任务时,它就会被占满,任务队列大小也是一,再提交一个任务时,他也会被沾满。如此一来,如果我们再提交任务时,其中已经没有可工作的线程了,队列中也没有多余的空位任务,只有被拒绝的命运。 按照这个思路我们来编写代码,编写一个runnable波任务task,定一个int类型的属性index,用于给任务编号,这样可以看到哪个任务被执行,哪个任务被拒绝,重载构造的方法用于初始化index,任务内容是输出当前线程名称和任务编号。接下来我们来执行该任务,使用ThreadPoolExecutor创建线程值,核心限制数为一,最大限制数也是一,说明线程池中只能存在一个线程,空闲线程存活时间为0,时间单位为秒,说明空闲线程不会被销毁任务,对你采用linkedblockingQueue队列长度为一,说明队列中只能存放一个任务任务,拒绝策略,采用discardPolicy,直接丢弃被拒绝的任务,向线程池中提交三个任务,三个任务的编号分别是123使用try-catch捕获拒绝执行异常。 写上finally代码块,在finally代码块中关闭线程池,至此main方法编写完成,整个例子也编写完成。执行程序观察执行结果,从执行结果来看,程序输出一二说明第三个任务没执行被丢弃了。测试结果符合预期。看完了第一个策略,再来看下一个策略,callerRunsPolicy。该策略是使用调用者线程直接执行被拒绝的任务。从源码中可以看到,当线程池没关闭时,直接调用任务的run方法,而这行代码就是使用调用者的线程执行的,线程池执行任务的途径只有通过execute和submit的方法,所以不会线程池执行的。 下面我们来演示该策略还是沿用之前的例子,将策略由discardPolicy改为callerRunsPolicy。例子改写完成再来执行程序,看看从执行结果来看,程序输出123,并且三是main线程打印的,事实证明被拒绝的任务的确是使用调用者的线程执行的,看完了第二个策略。再来看第三个策略,abortPolicy该策略是默认的拒绝策略,它的做法是抛出任务拒绝异常。从源码中可以看到方法体中只有一段抛异常的代码,下面我们来演示该策略,继续沿用之前的例子,将策略由callerRunsPolicy改为abroadPolicy,因此改写完成,再来执行程序看看。 从执行结果来看,程序输出1和2,还有拒绝执行异常测试结果符合预期。接下来我们再来看看最后一个策略,discardOldestPolicy。该策略是丢弃处于任务队列头部的人物,添加被拒绝的任务,从源码中可以看到,当线程池没被关闭时,调用任务队列的poll方法,该方的作用是移除队列头部元素,也就是移除队列头部任务,然后将被拒绝的任务重新提交给线程池。为了演示该策略,我们得改一改之前的任务队列容量,将任务队列容量加一,这样提交的第二个任务就会在队列的头部,第三个任务自然就在第二个任务的后面,此时任务队列被占满,在提交任务时会将第二个任务移出队列,第三个任务成为头部任务。 第四个任务添加成功,按照这个改动来编写代码还是之前的例子。首先将任务队列容量由一改为二,然后将测量由abroadPolicy改为discardOldestPolicy。接着再提交1个任务,一共是提交了4个任务,例子改写完成执行程序看看。从执行结果来看,程序输出134,果然第二个任务被移出了,队列。最后来总结一下本节内容,本节介绍4个任务拒绝策略,它们的作用这里就不再赘述了。在实际开发中abroadPolicy这种策略用的最多,我一般也是用它。当然了你可以制定任务,拒绝策略。

     

  • 相关阅读:
    基于Maven的MyBatis Generator逆向工程
    JQuery对象调用reset方法:Uncaught TypeError: $(...).reset is not a function
    死锁编码及定位分析
    线程池的简介及底层原理
    转载:Mysql8.0忘记 root 密码, 如何修改?
    synchronized 和 Lock 有什么区别?
    java 中的阻塞队列及生产者-消费者中的简单应用
    java 中 CountDownLatch、CyclicBarrier 和 Semaphore 的简单使用
    java中的公平锁、非公平锁、可重入锁、递归锁、自旋锁、独占锁和共享锁
    Java 集合类的线程安全问题及解决方法
  • 原文地址:https://www.cnblogs.com/cj8357475/p/16028399.html
Copyright © 2020-2023  润新知