热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

java定时任务_定时任务3种实现方式

java定时任务_定时任务3种实现方式定时任务在实际的开发中特别常见,比如电商平台30分钟后自动取消未支付的订单,以及凌晨的数据汇总和备份等ÿ

java定时任务_定时任务3种实现方式


  • 定时任务在实际的开发中特别常见,比如电商平台 30 分钟后自动取消未支付的订单,以及凌晨的数据汇总和备份等,都需要借助定时任务来实现,那么我们本文就来看一下定时任务最简单的几种实现方式。

Timer


  • Timer 是 JDK 自带的定时任务执行类,无论任何项目都可以直接使用 Timer 来实现定时任务,所以 Timer 的优点就是使用方便,它的实现代码如下:

    public class MyTimerTask {public static void main(String[] args) {// 定义一个任务TimerTask timerTask = new TimerTask() {@Overridepublic void run() {System.out.println("Run timerTask:" + new Date());}};// 计时器Timer timer = new Timer();// 添加执行任务(延迟 1s 执行,每 3s 执行一次)timer.schedule(timerTask, 1000, 3000);}
    }

  • 程序执行结果如下:

  • Run timerTask:Mon Aug 17 21:29:25 CST 2020
    Run timerTask:Mon Aug 17 21:29:28 CST 2020
    Run timerTask:Mon Aug 17 21:29:31 CST 2020

Timer 缺点分析


  • 任务执行时间长影响其他任务

  • 当一个任务的执行时间过长时,会影响其他任务的调度,如下代码所示:

    public class MyTimerTask {public static void main(String[] args) {// 定义任务 1TimerTask timerTask = new TimerTask() {@Overridepublic void run() {System.out.println("进入 timerTask 1:" + new Date());try {// 休眠 5 秒TimeUnit.SECONDS.sleep(5);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("Run timerTask 1:" + new Date());}};// 定义任务 2TimerTask timerTask2 = new TimerTask() {@Overridepublic void run() {System.out.println("Run timerTask 2:" + new Date());}};// 计时器Timer timer = new Timer();// 添加执行任务(延迟 1s 执行,每 3s 执行一次)timer.schedule(timerTask, 1000, 3000);timer.schedule(timerTask2, 1000, 3000);}
    }

  • 程序执行结果如下:

  • 进入 timerTask 1:Mon Aug 17 21:44:08 CST 2020
    Run timerTask 1:Mon Aug 17 21:44:13 CST 2020 Run timerTask 2:Mon Aug 17 21:44:13 CST 2020
    进入 timerTask 1:Mon Aug 17 21:44:13 CST 2020
    Run timerTask 1:Mon Aug 17 21:44:18 CST 2020
    进入 timerTask 1:Mon Aug 17 21:44:18 CST 2020
    Run timerTask 1:Mon Aug 17 21:44:23 CST 2020 Run timerTask 2:Mon Aug 17 21:44:23 CST 2020
    进入 timerTask 1:Mon Aug 17 21:44:23 CST 2020

  • 从上述结果中可以看出,当任务 1 运行时间超过设定的间隔时间时,任务 2 也会延迟执行。 原本任务 1 和任务 2 的执行时间间隔都是 3s,但因为任务 1 执行了 5s,因此任务 2 的执行时间间隔也变成了 10s(和原定时间不符)

  • 任务异常影响其他任务

  • 使用 Timer 类实现定时任务时,当一个任务抛出异常,其他任务也会终止运行,如下代码所示:

  • public class MyTimerTask {public static void main(String[] args) {// 定义任务 1TimerTask timerTask = new TimerTask() {@Overridepublic void run() {System.out.println("进入 timerTask 1:" + new Date());// 模拟异常int num = 8 / 0;System.out.println("Run timerTask 1:" + new Date());}};// 定义任务 2TimerTask timerTask2 = new TimerTask() {@Overridepublic void run() {System.out.println("Run timerTask 2:" + new Date());}};// 计时器Timer timer = new Timer();// 添加执行任务(延迟 1s 执行,每 3s 执行一次)timer.schedule(timerTask, 1000, 3000);timer.schedule(timerTask2, 1000, 3000);}
    }

  • 程序执行结果如下:

  • 进入 timerTask 1:Mon Aug 17 22:02:37 CST 2020
    Exception in thread "Timer-0" java.lang.ArithmeticException: / by zero
    at com.example.MyTimerTask$1.run(MyTimerTask.java:21)
    at java.util.TimerThread.mainLoop(Timer.java:555)
    at java.util.TimerThread.run(Timer.java:505)
    Process finished with exit code 0


Timer 小结


  • Timer 类实现定时任务的优点是方便,因为它是 JDK 自定的定时任务,但缺点是任务如果执行时间太长或者是任务执行异常,会影响其他任务调度,所以在生产环境下建议谨慎使用。

ScheduledExecutorService


  • ScheduledExecutorService 也是 JDK 1.5 自带的 API,我们可以使用它来实现定时任务的功能,也就是说ScheduledExecutorService 可以实现 Timer 类具备的所有功能,并且它可以解决了 Timer 类存在的所有问题

  • ScheduledExecutorService 实现定时任务的代码示例如下:

  • public class MyScheduledExecutorService {public static void main(String[] args) {// 创建任务队列ScheduledExecutorService scheduledExecutorService =Executors.newScheduledThreadPool(10); // 10 为线程数量// 执行任务scheduledExecutorService.scheduleAtFixedRate(() -> {System.out.println("Run Schedule:" + new Date());}, 1, 3, TimeUnit.SECONDS); // 1s 后开始执行,每 3s 执行一次}
    }

  • 程序执行结果如下:

  • Run Schedule:Mon Aug 17 21:44:23 CST 2020
    Run Schedule:Mon Aug 17 21:44:26 CST 2020
    Run Schedule:Mon Aug 17 21:44:29 CST 2020

  • 使用 ScheduledExecutorService 可以避免任务执行时间过长对其他任务造成的影响

  • 当任务 1 出现异常时,并不会影响任务 2 的执行


ScheduledExecutorService 小结


  • 在单机生产环境下建议使用 ScheduledExecutorService 来执行定时任务,它是 JDK 1.5 之后自带的 API,因此使用起来也比较方便,并且使用 ScheduledExecutorService 来执行任务,不会造成任务间的相互影响。

Spring Task


  • 如果使用的是 Spring 或 Spring Boot 框架,可以直接使用 Spring Framework 自带的定时任务,使用上面两种定时任务的实现方式,很难实现设定了具体时间的定时任务,比如当我们需要每周五来执行某项任务时,但如果使用 Spring Task 就可轻松的实现此需求
  • 以 Spring Boot 为例,实现定时任务只需两步:
  • 开启定时任务
  • 添加定时任务

开启定时任务


  • 开启定时任务只需要在 Spring Boot 的启动类上声明 @EnableScheduling 即可,实现代码如下:

  • @SpringBootApplication
    @EnableScheduling // 开启定时任务
    public class DemoApplication {// do someing
    }


添加定时任务


  • 定时任务的添加只需要使用 @Scheduled 注解标注即可,如果有多个定时任务可以创建多个 @Scheduled 注解标注的方法,示例代码如下:

  • import org.springframework.scheduling.annotation.Scheduled;
    import org.springframework.stereotype.Component;@Component // 把此类托管给 Spring,不能省略
    public class TaskUtils {// 添加定时任务@Scheduled(cron = "59 59 23 0 0 5") // cron 表达式,每周五 23:59:59 执行public void doTask(){System.out.println("我是定时任务~");}
    }

  • 定时任务是自动触发的无需手动干预,也就是说 Spring Boot 启动后会自动加载并执行定时任务。


推荐阅读
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 展开全部下面的代码是创建一个立方体Thisexamplescreatesanddisplaysasimplebox.#Thefirstlineloadstheinit_disp ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 本文介绍了一个Java猜拳小游戏的代码,通过使用Scanner类获取用户输入的拳的数字,并随机生成计算机的拳,然后判断胜负。该游戏可以选择剪刀、石头、布三种拳,通过比较两者的拳来决定胜负。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • 本文介绍了Java高并发程序设计中线程安全的概念与synchronized关键字的使用。通过一个计数器的例子,演示了多线程同时对变量进行累加操作时可能出现的问题。最终值会小于预期的原因是因为两个线程同时对变量进行写入时,其中一个线程的结果会覆盖另一个线程的结果。为了解决这个问题,可以使用synchronized关键字来保证线程安全。 ... [详细]
  • 本文详细介绍了Spring的JdbcTemplate的使用方法,包括执行存储过程、存储函数的call()方法,执行任何SQL语句的execute()方法,单个更新和批量更新的update()和batchUpdate()方法,以及单查和列表查询的query()和queryForXXX()方法。提供了经过测试的API供使用。 ... [详细]
  • 本文介绍了UVALive6575题目Odd and Even Zeroes的解法,使用了数位dp和找规律的方法。阶乘的定义和性质被介绍,并给出了一些例子。其中,部分阶乘的尾零个数为奇数,部分为偶数。 ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • Go Cobra命令行工具入门教程
    本文介绍了Go语言实现的命令行工具Cobra的基本概念、安装方法和入门实践。Cobra被广泛应用于各种项目中,如Kubernetes、Hugo和Github CLI等。通过使用Cobra,我们可以快速创建命令行工具,适用于写测试脚本和各种服务的Admin CLI。文章还通过一个简单的demo演示了Cobra的使用方法。 ... [详细]
  • r2dbc配置多数据源
    R2dbc配置多数据源问题根据官网配置r2dbc连接mysql多数据源所遇到的问题pom配置可以参考官网,不过我这样配置会报错我并没有这样配置将以下内容添加到pom.xml文件d ... [详细]
author-avatar
手机用户2602938525
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有