Java 中的定时任务(一)
定时任务简单来说就是在指定时间,指定的频率来执行一个方法,而在 Java 中我们又该如何实现呢?
想来主要有 3 种方式,最原始的方式肯定是开启一个线程,让它睡一会跑一次睡一会跑一次这也就达到了定频率的执行 run 方法,我们只需要将业务逻辑写在 run 方法中即可。这种方式总结就是单个线程来执行单个任务。
方式一:创建一个线程
package com.yu.task;
import java.util.Date;
public class ThreadTest {
public static void main(String[] args) {
// 设置执行周期
final long timeInterval = 3000;
Runnable runnable = new Runnable() {
public void run() {
while (true) {
System.out.println("Task Run ... " + new Date());
try {
Thread.sleep(timeInterval);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
Thread thread = new Thread(runnable);
thread.start();
}
}
第二种方式:使用 JDK 自带的 API Timer 以及 TaskTimer。
这种方式和第一种简单粗暴的方式有什么区别呢,主要体现在使用 API 可以在指定的时间开始启动任务,可以延期执行首次任务,同样也看可以设置一定的时间间隔,但是原理是是一样的,后台还是启动了一个线程,应该说是只有一个线程在执行任务,不管我们启动的 Task 有几个。所以这也会有问题,比方说一个一个任务没有执行完成,另一个任务就开始执行了,可能会发生并发问题。还有若是一个任务中报错,则线程就会被停止。
package com.yu.task; import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask; public class MyTask extends TimerTask{ private String name; public MyTask(String name) {
this.name = name;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} @Override
public void run() {
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String format = sf.format(new Date());
System.out.println("exec MyTask ... 当前时间为:" + format);
System.out.println(this.name +" 正在执行!" + sf.format(new Date()));
} public static void main(String[] args) {
Timer timer = new Timer();
TimerTask task1 = new MyTask("Tasks 1");
TimerTask task2 = new MyTask("Tasks 2"); Calendar calendar1 = Calendar.getInstance();
calendar1.add(Calendar.SECOND, 3);
Calendar calendar2 = Calendar.getInstance();
calendar2.add(Calendar.SECOND, 5); SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String format = sf.format(new Date());
System.out.println("当前时间为:" + format); timer.schedule(task1, calendar1.getTime(), 3000L);
timer.schedule(task2, calendar2.getTime(), 3000L);
} }
其实在 Timer 中,封装了一个 Task 的队列和 Time 的线程对象,我们自定义的 Task 的引用会放在队列中等待执行。
大致是这么一个关系 Timer - TimerThread - TaskQueue - MyTask - run 当然最终执行的方法肯定是我们自定义任务中的 run 方法。因为我们自定义的任务已经继承了 TimeTask ,而这个类已经实现了 Runnable 接口。
Timer 定时器第一种方式好的地方还在于可以选择关闭任务,查看任务的执行情况等。下面介绍几个相关的方法。
启动定时任务也有几个不同的方法,每个都有不同的使用场景。

上面是 Timer 类中的属性和方法的简图,开启一个任务我们主要使用 6 个方法, 一共 3 组,先看简单的
schedule() 方法中含有两个参数,主要是用来执行一次任务的,不存在频率的问题,而 3 个参数表示执行什么任务,什么时候开始执行/延时多久执行,多久执行一次。
现在来假设一个场景,01秒开始执行一个任务,频率是 3 秒执行一次,不知道你们有没有想到这个情况,若是这个方法本身执行需要 4 秒,那第二次执行的时间是 04 呢? 还是 05 秒呢?
而这个差别就是 schedule 和 scheduleAtFixedRate 方法的区别,前者会按照任务执行的情况来执行下一次任务,也就是说 01 之后,会等第一次执行结束再开始第二次,这样就会带来一个问题,每次执行时间都比预想的要晚。而 scheduleAtFixedRate 则不存在这个问题,它会按照指定的时间和频率执行,这样坐就会出现,同一时刻会有两个任务在同时执行,若是,可能会发生并发问题。
上面讨论的是当任务本身执行的时间大于频率时,两个方法不同的执行情况,还有一个情况,若是当前时间晚于我们设定的开始执行时间又会怎么办呢?
schedule () 会比较符合正常思维,晚了就晚了,现在开始执行就是,不存在补回的情况,但是 scheduleAtFixedRate 则会一次性补回未执行的次数。举例来说,当前时间为 09,而我们设定的开始时间为 00 ,频率为 3 秒,则 schedule 会在 09 执行一次,12 执行一次。而 scheduleAtFixedRate 会在 09 一次性执行 4 次,12 执行一次,后面就是正常的频率。
下面再说几个可能会起到锦上添花作用的方法,我们的若是想取消任务的执行,有一个方法但是分为两个类执行,我们可以调用 TimeTask 中的 cancel 方法,这个方法只对当前任务有效,若是想取消全部的任务,则需要调用 Timer 中的 cancel 方法。
那有该如何查看定时器 Timer 中已经被取消任务的数量呢?当然还是有方法的,那就是 Timer 中的 purge 方法。
说了这么说,实际上我们可以看到,Timer 定时器本身还是调用线程来完成定时操作。且后台只有一个多线程 TimeThread 在工作。
那 Timer 定时器有什么缺点呢?
1 并发操作时的缺陷,这是因为 Timer 的后台只有一个执行线程导致的,容易引起并发问题。
2 任务抛出异常时缺陷。如果 TimeTask 抛出 RuntimeException,Timer 会停止所有任务的执行。
所以以后我们在使用 Timer 定时器的时候要注意,这两个情况,多任务且并发执行的时候不要使用 Timer,复杂任务调度的时候也不要使用 Timer ,因为一个不小心出现异常了,所有任务都卡壳了。但是,Timer 定时器处理一些简单的定是任务还是非常方便的!比方说我想实现的,定时发送邮件。用起来就很是方便,因为这是 JDK 自带的 API 呀!
第三种方式:使用 Java 中的专门用于定时任务管理的框架 Quartz 。(还没学,等等吧……)
上面也说了 Timer 定时器的弊端,怎么办,据听说 Quartz 可以解决这些……
后记:据我知道,Java 中定时任务也就这几个吧,欢迎补充,有好多人说到某某框架中有定时任务,我想说的是,那不是!那是框架集成了上面说的定时任务框架,可能集成的就是 Quartz,或是 Quartz 的简化版本……
Java 中的定时任务(一)的更多相关文章
- 转:java中的定时任务
引自:http://www.cnblogs.com/wenbronk/p/6433178.html java中的定时任务, 使用java实现有3种方式: 1, 使用普通thread实现 @Test p ...
- Java中的定时任务
现代的应用程序早已不是以前的那些由简单的增删改查拼凑而成的程序了,高复杂性早已是标配,而任务的定时调度与执行也是对程序的基本要求了. 很多业务需求的实现都离不开定时任务,例如,每月一号,移动将清空你上 ...
- java中实现定时任务 task 或quartz
转载大神的 https://www.cnblogs.com/hafiz/p/6159106.html https://www.cnblogs.com/luchangyou/p/6856725.html ...
- java中的定时任务小示例
package package_1; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Timer; ...
- java中实现定时功能
网上资料: 我们可以使用Timer和TimerTask类在java中实现定时任务,详细说明如下: 1.基础知识java.util.Timer一种线程设施,用于安排以后在后台线程中执行的任务.可安排任务 ...
- java中基于TaskEngine类封装实现定时任务
主要包括如下几个类: 文章标题:java中基于TaskEngine类封装实现定时任务 文章地址: http://blog.csdn.net/5iasp/article/details/10950529 ...
- 在Java Web项目中添加定时任务
在Java Web程序中加入定时任务,这里介绍两种方式:1.使用监听器注入:2.使用Spring注解@Scheduled注入. 推荐使用第二种形式. 一.使用监听器注入 ①:创建监听器类: impor ...
- 如何用 Java 实现 Web 应用中的定时任务?
定时任务,是指定一个未来的时间范围执行一定任务的功能.在当前WEB应用中,多数应用都具备任务调度功能,针对不同的语音,不同的操作系统, 都有其自己的语法及解决方案,windows操作系统把它叫做任务计 ...
- 如何用 Java 实现 Web 应用中的定时任务
定时任务,是指定一个未来的时间范围执行一定任务的功能.在当前WEB应用中,多数应用都具备任务调度功能,针对不同的语音,不同的操作系统, 都有其自己的语法及解决方案,windows操作系统把它叫做任务计 ...
随机推荐
- Elasticsearch技术解析与实战(二)文档的CRUD操作
启动Elasticsearch和kibana 访问Elasticsearch:http://localhost:9200/?pretty 访问kibana:http://localhost:5601 ...
- [译]Quartz.NET 框架 教程(中文版)2.2.x 之第八课 调度监听器
第八课 调度监听器 调度监听器和触发监听器和触发监听器.作业任务监听器非常相似,只是调度监听器在调度器内接收通知事件,而不需要关联具体的触发器或作业任务事件. 跟调度监听器相关的事件,添加作业任务/触 ...
- [整理]C语言中的a,&a和&a[0]
#include<stdio.h> int main(void) { int a[]={1,2,3}; printf("%0X\n",a); // a的类型原本是int ...
- OK6410 rmmod卸载模块失败:No such file or directory -- 转
原文地址:http://hi.baidu.com/andio/item/b8be9810282841433a176e86 rmmod chdir no such file or directory 说 ...
- oracle同义词是什么意思?
相当于alias,比如把user1.table1 在user2中建一个同义词table1create synonym table1 for user1.table1;这样当我们在user2中查sele ...
- REX系统2
REX(Real Time Executive)是一个面向嵌入式应用的,简单高效的,抢先式,多任务实时操作系统,支持基于优先级的任务调度算法(支持优先级反转).它提供了任务控制,任务同步,互斥,定时器 ...
- Monkeyrunner的相关总结
1.1 monkeyrunner API 主要包括三个模块1.MonkeyRunner:这个类提供了用于连接monkeyrunner和设备或模拟器的方法,它还提供了用于创建用户界面显示提供了方法.2 ...
- 关于 JVM 内存的 N 个问题(转)
JVM的内存区域是怎么划分的? JVM的内存划分中,有部分区域是线程私有的,有部分是属于整个JVM进程:有些区域会抛出OOM异常,有些则不会,了解JVM的内存区域划分以及特征,是定位线上内存问题的基础 ...
- Owin WebApi版本控制
public class WebApiControllerSelector : IHttpControllerSelector { private const string NamespaceKey ...
- CRF条件随机场
CRF的进化 https://flystarhe.github.io/2016/07/13/hmm-memm-crf/参考: http://blog.echen.me/2012/01/03/intro ...