Java中实现定时任务的3种方法!

今天我们不用任何框架,用最朴素的 Java API 来实现定时任务,本文会介绍 3 种实现方案,我们一起来看...

1、 sleep

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

实现逻辑:

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

实现代码如下:

/*** 休眠实现定时任务*/
private static void sleepTask() {new Thread(() -> {while (true) {System.out.println("hi, 欢迎关注:Java技术栈");try {// 每隔3秒执行一次Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}}}).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 方法里去实现。

实现代码如下:

/*** timer定时任务*/
private static void timerTask() throws InterruptedException {Timer timer = new Timer();TimerTask timerTask = new TimerTask() {@Overridepublic void run() {System.out.println("hi, 欢迎关注");}};// 第一次任务延迟时间long delay = 2000;// 任务执行频率long period = 3 * 1000;// 开始调度timer.schedule(timerTask, delay, period);// 指定首次运行时间
// timer.schedule(timerTask, DateUtils.addSeconds(new Date(), 5), period);Thread.sleep(20000);// 终止并移除任务timer.cancel();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 调度的。

实现代码如下:

/*** 线程池定时任务*/
public static void poolTask(){ScheduledExecutorService pool = Executors.newScheduledThreadPool(10);pool.scheduleAtFixedRate(() -> {System.out.println("hi, 欢迎关注");}, 2000, 3000, TimeUnit.MILLISECONDS);
}

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

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

总结

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

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


往期推荐

定时任务的实现原理,看完就能手撸一个!


一口气说出 6 种延时队列的实现方法,面试官满意的笑了


JDK 9 对字符串 String 的优化,挺有意思!


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/544928.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

回文子序列_计算回文子序列的总数

回文子序列Problem statement: 问题陈述&#xff1a; Given a string str, find total number of possible palindromic sub-sequences. A sub-sequence does not need to be consecutive, but for any xixj i<j must be valid in the parent string too. Like "icl&q…

【Microsoft Azure学习之旅】测试消息队列(Service Bus Queue)是否会丢消息

组里最近遇到一个问题&#xff0c;微软的Azure Service Bus Queue是否可靠&#xff1f;是否会出现丢失消息的情况&#xff1f; 具体缘由如下&#xff0c; 由于开发的产品是SaaS产品&#xff0c;为防止消息丢失&#xff0c;跨Module消息传递使用的是微软Azure消息队列&#xff0…

使用SharedPreferences存储和读取数据

转&#xff1a;http://www.worlduc.com/blog2012.aspx?bid19403392 1、任务目标 &#xff08;1&#xff09;掌握Android中SharedPreferences的使用方法。 2、任务陈述 &#xff08;1&#xff09;运行后&#xff0c;显示如下界面&#xff0c;可以写入和读取SharedPreferences中…

Zookeeper 的 5 大核心知识点!

1 ZooKeeper简介ZooKeeper 是一个开源的分布式协调框架&#xff0c;它的定位是为分布式应用提供一致性服务&#xff0c;是整个大数据体系的管理员。ZooKeeper 会封装好复杂易出错的关键服务&#xff0c;将高效、稳定、易用的服务提供给用户使用。如果上面的官方言语你不太理解&…

PHP | 计算字符串中的单词总数

Given a string and we have to count the total number of words in it. 给定一个字符串&#xff0c;我们必须计算其中的单词总数。 str_word_count() function str_word_count()函数 To find the total number of words in a string, we can use str_word_count() function…

parted分区介绍

简介: 当硬盘或raid后,硬盘大于2T的时候,可以使用parted进行分区; 使用parted的前提是操作系统已经安装部署完成; 大于2T的硬盘在安装部署阶段可以使用raid的虚拟磁盘技术分区,如分出100G安装系统,剩余的在安装系统后,使用parted进行分区; 1.parted非交互式分区: …

SharedPreferences详解

我们在开发软件的时候,常需要向用户提供软件参数设置功能,例如我们常用的微信,用户可以设置是否允许陌生人添加自己为好友.对于软件配置参数的保存,如果是在window下通常我们会采用ini文件进行保存.如果是J2EE下面,我们会采用properties属性文件或者xml进行保存.在我们的Androi…

【视频版】最新版Swagger 3升级指南和新功能体验!

作者 | 王磊来源 | Java中文社群&#xff08;ID&#xff1a;javacn666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;Swagger 3.0 发布已经有一段时间了&#xff0c;它于 2020.7 月 发布&#xff0c;但目前市面上使用的主流版本还是 Swagger 2…

java treemap_Java TreeMap pollFirstEntry()方法与示例

java treemapTreeMap类pollFirstEntry()方法 (TreeMap Class pollFirstEntry() method) pollFirstEntry() method is available in java.util package. pollFirstEntry()方法在java.util包中可用。 pollFirstEntry() method is used to return and then remove the entry (key-…

各大厂面试高频的面试题新鲜出炉,你能答上几道?

关于生产环境如何配置线程数&#xff0c;还是要根据业务来进行区分&#xff0c;我们时常会听到什么IO密集型、CPU密集型任务...那么这里提一个问题&#xff1a;大家知道什么样的任务或者代码会被认定为IO/CPU密集&#xff1f;又是用什么样的标准来认定IO/CPU密集&#xff1f;如…

c/c++如何获取数组的长度

2019独角兽企业重金招聘Python工程师标准>>> C、C中没有提供 直接获取数组长度的函数&#xff0c;对于存放字符串的字符数组提供了一个strlen函数获取长度&#xff0c;那么对于其他类型的数组如何获取他们的长度呢&#xff1f;其中一种方法是使 用sizeof(array) / s…

JSP JAVA 自定义 错误页面(404,505,500)

当网站页面找不到或者服务器内部出错的时候&#xff0c;我们不想让用户看到默认的那张 404&#xff0c;500 的错误页面&#xff0c;那要是想自己做一张 找不到页面的页面改怎么做呢&#xff1f;在 web .xml 文件中 加入下面的语句就能达到这个效果<error-page><error-…

【送给读者】全新苹果 AirPods,包邮送一套!

为回馈长期以来科创人读者对本栏目的关注支持&#xff0c;本周小编联合了计算机领域八位高质量原创号主一起为大家送出一套 全新苹果AirPods 2代。以下推荐的公号原创率都很高&#xff0c;均为个人IP号&#xff0c;有些小伙伴应该已经关注部分公号。本次抽奖采用第三方抽奖小程…

java 方法 示例_Java扫描仪的hasNextBoolean()方法与示例

java 方法 示例扫描器类的hasNextBoolean()方法 (Scanner Class hasNextBoolean() method) hasNextBoolean() method is available in java.util package. hasNextBoolean()方法在java.util包中可用。 hasNextBoolean() method is used to check whether this Scanners next in…

进程控制(kill)

为什么80%的码农都做不了架构师&#xff1f;>>> kill&#xff1a;终止进程&#xff08;或传送信号到某进程&#xff09; kill [options] [process_ids] kill命令可以发送信号给进程&#xff0c;可以终止&#xff08;terminate&#xff09;&#xff08;默认操作&a…

oracle怎样修改表名、列名、字段类型、添加表列、删除表列

ALTER TABLE SCOTT.TEST RENAME TO TEST1--修改表名 ALTER TABLE SCOTT.TEST RENAME COLUMN NAME TO NAME1 --修改表列名 ALTER TABLE SCOTT.TEST MODIFY NAME1 NUMBER(20) --修改字段类型 ALTER TABLE SCOTT.TEST ADD ADDRESS VARCHAR2(40) --添加表列 ALTER TABLE SCOTT.TEST…

TextArea里Placeholder换行问题

转&#xff1a;http://www.tuicool.com/articles/feYVNf 页面上使用TextArea控件时&#xff0c;会时不时的想给个提示&#xff0c;比如按照一定方式操作之类的。 正常情况下&#xff0c;会使用Placeholder&#xff0c;但这样的提示是不会换行的&#xff0c;无论是用\r\n&…

printstream_Java PrintStream clearError()方法与示例

printstreamPrintStream类clearError()方法 (PrintStream Class clearError() method) clearError() method is available in java.io package. clearError()方法在java.io包中可用。 clearError() method is used to clear the internal error state of this PrintStream. cle…

uniq用法详解

uniquniq命令可以去除排序过的文件中的重复行&#xff0c;因此uniq经常和sort合用。也就是说&#xff0c;为了使uniq起作用&#xff0c;所有的重复行必须是相邻的。uniq语法[rootwww ~]# uniq [-icu]选项与参数&#xff1a;-i &#xff1a;忽略大小写字符的不同&#xff1b;-…

Swagger增强神器:Knife4j!用它轻松实现接口搜索、Word下载、接口过滤...

视频版内容&#xff1a;Swagger 是开发中最常用的框架之一了&#xff0c;但 Swagger 本身又有很多不完善的地方&#xff0c;比如&#xff0c;在众多的接口中查询某一个接口&#xff0c;又或者是把所有的接口导出成 Word 格式等&#xff0c;都无法在 Swagger 中实现。有人可能会…