Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 1050|回复: 0

JAVA线程池ScheduledExecutorService周期性地执行任务 与单个Thread周期性执行任务的异常处理

[复制链接]
  • TA的每日心情
    奋斗
    2024-11-24 15:47
  • 签到天数: 804 天

    [LV.10]以坛为家III

    2053

    主题

    2111

    帖子

    72万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    726782
    发表于 2021-5-20 17:13:15 | 显示全部楼层 |阅读模式

    本文记录:

    1,使用ScheduledExecutorService的 scheduleAtFixedRate 方法执行周期性任务的过程,讨论了在任务周期执行过程中出现了异常,会导致周期任务失败。

    2,使用普通的Thread类来执行任务,在main线程中周期性创建线程,提交任务。然后,使用UncaughtExceptionHandler来处理异常。 

     

    一,正常任务执行

    负责执行任务的线程类如下:(一个计算阶乘的任务,计算5以上的阶乘,就会抛出异常)

     1 public class FactorialCalc implements Runnable {
     2 
     3     private Integer number;
     4 
     5     public FactorialCalc(Integer number) {
     6         this.number = number;
     7     }
     8 
     9     public void run() {
    10 
    11         int result = 1;
    12 
    13         if (number == 0) {
    14             System.out.println("0!=" + "1");
    15         }
    16 
    17         if (number > 5) {
    18             System.out.println("exception");
    19             throw new IllegalArgumentException(">5");
    20         }
    21 
    22         for(int i = 1; i <= number; i++) {
    23             result *= i;
    24 
    25         }
    26         System.out.println(number + "!=" + result);
    27     }
    28 }

     

    测试的Main类如下:

     1 public class MainPeriod {
     2 
     3     public static void main(String[] args) {
     4 
     5         ScheduledExecutorService executorService = Executors.newScheduledThreadPool(2);
     6 
     7         FactorialCalc task1 = new FactorialCalc(6);
     8         FactorialCalc task2 = new FactorialCalc(3);
     9 
    10         ScheduledFuture<?> result = executorService.scheduleAtFixedRate(task1, 0, 1, TimeUnit.SECONDS);
    11 //       ScheduledFuture<?> result =  executorService.scheduleAtFixedRate(task2, 0, 2, TimeUnit.SECONDS);
    12 
    13         try {
    14             TimeUnit.SECONDS.sleep(5);
    15             executorService.shutdown();
    16         } catch (InterruptedException e) {
    17             e.printStackTrace();
    18         }
    19     }
    20 }

     

    ScheduledFuture<?> result = executorService.scheduleAtFixedRate(task1, 0, 1, TimeUnit.SECONDS);

    提交一个Runnable任务,延迟为0,每1秒钟执行一次。

     

    二,线程 执行过程中出现异常

    当提交 task1 时,线程在执行过程中会抛出异常。

            FactorialCalc task1 = new FactorialCalc(6);//计算6的阶乘,6大于5
    
            ScheduledFuture<?> result = executorService.scheduleAtFixedRate(task1, 0, 1, TimeUnit.SECONDS);

    此时,如果注释掉 //executorService.shutdown(); 则线程池不会中止,因为这是一个线程池,所有的异常都由线程池catch住了但是由于线程执行过程中抛出了异常,任务也不会周期性地执行了。参考JDK里面的scheduleAtFixedRate注释:

     * If any execution of the task * encounters an exception, subsequent executions are suppressed. public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
                                                      long initialDelay,
                                                      long period,
                                                      TimeUnit unit);

     

    三,关闭线程池 ,执行 executorService.shutdown() 语句

    若线程池线程 执行任务过程中抛出了异常,但是在 主线程中 执行了executorService.shutdown() 语句,则会正常关闭 线程池。

     

    四,总结

    使用ScheduledExecutorService的 scheduleAtFixedRate 方法执行周期性任务时,如果任务一直正常执行,则任务会按设定的执行周期一直在运行(前提是,主线程内不要调用executorService.shutdown() ,比如需要 执行 永久性的周期性任务,那就不能调用 executorService.shutdown() )。

    如果任务在某次执行过程中抛出了异常,则周期性任务会被中断,后续也不会再生成任务了,如果主线程 也没有 调用 executorService.shutdown() ,那线程池就不会关闭了。

     

    五,使用Thread类执行任务,在Main线程中通过while循环周期性提交任务,使用UncaughtExceptionHandler来处理异常

     1 import java.util.Random;
     2 import java.util.concurrent.TimeUnit;
     3 
     4 public class Main {
     5 
     6     public static void main(String[] args) {
     7         
     8         Random rand = new Random();
     9         
    10         while(true){
    11             int number = rand.nextInt(10);
    12             Thread t = new Thread(new FactorialCalc(number));
    13             t.setUncaughtExceptionHandler(new ExceptionHandler());
    14             t.start();
    15             try{
    16                 System.out.println("sleep 4s for next task");
    17                 TimeUnit.SECONDS.sleep(4);
    18             }catch(InterruptedException e){
    19                 
    20             }
    21         }
    22     }
    23 }

     在main方法中使用一个while(true)循环,周期性地创建线程 提交任务。

    第12-13行,每创建一个线程,调用setUncaughtExceptionHandler方法设置异常处理。关于异常处理,可参考:JAVA线程未捕获异常处理

    第15-18行,线程每隔4s提交一次任务,从而实现任务的周期性执行。 

     

    异常处理类ExceptionHandler类实现了UncaughtExceptionHandler接口,然后在uncaughtException方法里面定义具体的异常处理过程即可。

    import java.lang.Thread.UncaughtExceptionHandler;
    
    public class ExceptionHandler implements UncaughtExceptionHandler{
    
        @Override
        public void uncaughtException(Thread t, Throwable e) {
            System.out.println("illegal exception: 计算的阶乘大于5了," + e.getMessage());
        }
    }

     

    与线程池方式相比 ,这种方式是每个周期,都要new一个线程。而线程池则是每个周期new一个任务,把任务提交给线程池即可。

    原文:http://www.cnblogs.com/hapjin/p/7616068.html

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2025-2-3 03:58 , Processed in 0.059588 second(s), 28 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表