不用任何框架,Java 就能实现定时任务的三种方法

开发 后端
新开一个线程,添加一个 for/ while 死循环,然后在死循环里面添加一个 sleep 休眠逻辑,让程序每隔 N 秒休眠再执行一次,这样就达到了一个简单定时任务的效果。

[[386391]]

是的,不用任何框架,用我们朴素的 Java 编程语言就能实现定时任务。

今天,栈长就介绍 3 种实现方法,教你如何使用 JDK 实现定时任务!

1、 sleep

这也是我们最常用的 sleep 休眠大法,不只是当作休眠用,我们还可以利用它很轻松的能实现一个简单的定时任务。

实现逻辑:

新开一个线程,添加一个 for/ while 死循环,然后在死循环里面添加一个 sleep 休眠逻辑,让程序每隔 N 秒休眠再执行一次,这样就达到了一个简单定时任务的效果。

实现代码如下:

  1. /** 
  2.  * 休眠实现定时任务 
  3.  * 来源公众号:Java技术栈 
  4.  */ 
  5. private static void sleepTask() { 
  6.     new Thread(() -> { 
  7.         while (true) { 
  8.             System.out.println("hi, 欢迎关注:Java技术栈"); 
  9.  
  10.             try { 
  11.                 // 每隔3秒执行一次 
  12.                 Thread.sleep(3000); 
  13.             } catch (InterruptedException e) { 
  14.                 e.printStackTrace(); 
  15.             } 
  16.         } 
  17.     }).start(); 

这种方式比较傻瓜化了,只能按固定频率运行,不能指定具体运行的时间。

另外,上面的箭头语法,栈长使用了 JDK 8 中的 Lambda 表达式,这里就不再撰述了。

2、Timer

来看下 JDK 自带的 java.util.Timer 类:

JDK 1.3 就内置了 java.util.Timer 类,可以用来调度 java.util.TimerTask 任务。

几个重要的方法:

  • schedule:开始调度任务,提供了几个包装方法;
  • cancle:终止任务调度,取消当前调度的所有任务,正在运行的任务不受影响;
  • purge:从任务队列中移除所有已取消的任务;

另外,java.util.TimerTask 就是实现了 Runnable 接口,具体任务逻辑则是在 run 方法里去实现。

实现代码如下:

  1. /** 
  2.  * timer定时任务 
  3.  * 来源公众号:Java技术栈 
  4.  */ 
  5. private static void timerTask() throws InterruptedException { 
  6.     Timer timer = new Timer(); 
  7.  
  8.     TimerTask timerTask = new TimerTask() { 
  9.         @Override 
  10.         public void run() { 
  11.             System.out.println("hi, 欢迎关注:Java技术栈"); 
  12.         } 
  13.     }; 
  14.  
  15.     // 第一次任务延迟时间 
  16.     long delay = 2000; 
  17.  
  18.     // 任务执行频率 
  19.     long period = 3 * 1000; 
  20.  
  21.     // 开始调度 
  22.     timer.schedule(timerTask, delay, period); 
  23.      
  24.     // 指定首次运行时间 
  25. // timer.schedule(timerTask, DateUtils.addSeconds(new Date(), 5), period); 
  26.  
  27.     Thread.sleep(20000); 
  28.  
  29.     // 终止并移除任务 
  30.     timer.cancel(); 
  31.     timer.purge(); 

这种实现方式比较简单,可以指定首次执行的延迟时间、首次执行的具体日期时间,以及执行频率,能满足日常需要。

另外,需要注意的是,Timer 是线程安全的,因为背后是单线程在执行所有任务。

Timer 也会有一些缺陷:

  • Timer 是单线程的,假如有任务 A,B,C,任务 A 如果执行时间比较长,那么就会影响任务 B,C 的启动和执行时间,如果 B,C 执行时间也比较长,那就会相互影响;
  • Timer 不会捕获异常,如果 A,B,C 任何一个任务在执行过程中发生异常,就会导致 TImer 整个定时任务停止工作;
  • Timer 是基于绝对时间调度的,而不是基于相对时间,所以它对系统时间的改变非常敏感;

所以,如果在使用 Timer 的过程中要注意这些缺陷,虽然可以用,但不推荐。

3、ScheduledExecutorService

因 Timer 有一些缺陷,所以不太建议使用 Timer,推荐使用 ScheduledExecutorService:

ScheduledExecutorService 即是 Timer 的替代者,JDK 1.5 并发包引入,是基于线程池设计的定时任务类:

java.util.concurrent.Executors.newScheduledThreadPool

上了线程池,每个调度任务都会分配到线程池中的某一个线程去执行,任务就是并发调度执行的,任务之间互不影响。

几个重要的调度方法:

  • schedule:只执行一次调度;
  • scheduleAtFixedRate:按固定频率调度,如果执行时间过长,下一次调度会延迟,不会同时执行;
  • scheduleWithFixedDelay:延迟调度,上一次执行完再加上延迟时间后执行;

另外,可以看出,任务是支持 Runnable 和 Callable 调度的。

实现代码如下:

  1. /** 
  2.  * 线程池定时任务 
  3.  * 来源公众号:Java技术栈 
  4.  */ 
  5. public static void poolTask(){ 
  6.     ScheduledExecutorService pool = Executors.newScheduledThreadPool(10); 
  7.  
  8.     pool.scheduleAtFixedRate(() -> { 
  9.         System.out.println("hi, 欢迎关注:Java技术栈"); 
  10.     }, 2000, 3000, TimeUnit.MILLISECONDS); 

这是一个按固定频率调度的任务,创建了 10 个核心线程数,首次执行延迟 2 秒,后续每 3 秒执行一次。

这种方式简单、好用,避免了使用 Timer 带来的各种问题,推荐使用这种实现方式。

总结

好了,本文栈长分享了 3 种 Java 实现定时任务的方式,也相对简单,但执行频率时间设置都太简单,只适合简单的业务,不适合实际复杂业务的需求,实际业务要考虑分布式、故障转移恢复等远要复杂的多。

本文仅给大家一个参考吧,在不用框架的前提下也能实现定时任务,在小而美的场景,还是很香的。

本节教程所有实战源码已上传到这个仓库: 

https://github.com/javastacks/javastack

本文转载自微信公众号「Java技术栈」,可以通过以下二维码关注。转载本文请联系Java技术栈公众号。

 

责任编辑:武晓燕 来源: Java技术栈
相关推荐

2024-09-20 05:49:04

SpringBoot后端

2021-07-13 12:31:27

IT组织改进首席技术官

2013-01-04 15:47:54

Android开发平铺UI设计

2024-01-22 08:53:00

策略任务RocketMQ

2024-01-31 08:38:57

Python定时任务函数

2024-02-26 11:12:33

定时任务线程

2021-11-22 12:35:40

Python命令定时任务

2009-07-08 12:56:32

编写Servlet

2016-10-12 13:53:38

JavaByteBufferRandomAcces

2021-12-20 07:11:26

Java List排序 Java 基础

2009-06-22 13:30:00

定时任务Java

2011-06-10 10:43:12

Ubuntu应用安装

2009-06-23 10:45:18

Hibernate支持

2015-12-11 09:24:38

加密数据Linux

2010-09-14 15:10:49

CSS注释

2009-12-11 18:49:39

预算编制博科资讯

2011-04-18 15:32:45

游戏测试测试方法软件测试

2022-07-13 16:06:16

Python参数代码

2024-11-15 07:00:00

Python发送邮件

2023-08-14 17:58:13

RequestHTTP请求
点赞
收藏

51CTO技术栈公众号