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操作系统把它叫做任务计 ...
随机推荐
- Python 豆瓣顶帖
由于在豆瓣发了个租房帖子,发现很快就被其他的帖子淹没,但是手动顶帖实在太累,
- 部署elasticsearch遇到的问题
为增加搜索功能,最近在自己的服务器上部署elasticsearch,折腾一下,把注意的问题记录一下. 1. 因为最近的es5.5.2要求java1.8,所以确保java版本正确. 2. 我的服务器只 ...
- AngularJS - 下一个大框架
AngularJS AngularJS是web应用的下一个巨头. AngularJS如果为创建web应用而设计,那它就是HTML的套路了.具有数据绑定, MVW, MVVM, MVC, 依赖注入的声明 ...
- thinkphp 带条件分页查询
thinkphp 带条件分页查询:form表单传值时候,method='get'. 用 get 传值
- python模块-platform
#author:Blood_Zero #coding:utf- import platform print dir(platform) #获取platform函数功能 platform.archite ...
- 【navicat112_premium】navicat112_premium数据库连接工具安装过程
此工具及其方便,可以连接mysql.oracle.sqlserver登数据库... 1.下载安装包Navicat Premium_11.2.7简体中文版.rar 下载地址:http://qiaoliq ...
- Python图片验证码降噪 — 8邻域降噪
简介 图片验证码识别的可以分为几个步骤,一般用 Pillow 库或 OpenCV 来实现,这几个过程是: 1.灰度处理&二值化 2.降噪 3.字符分割 4.标准化 5.识别 所谓降噪就是把不需 ...
- 内核定时器的使用(好几个例子add_timer)【转】
转自:http://blog.csdn.net/jidonghui/article/details/7449546 LINUX内核定时器是内核用来控制在未来某个时间点(基于jiffies)调度执行某个 ...
- vue项目中遇到的一些问题
或访问:https://github.com/littleHiuman/experiences-about-vue 欢迎补充! vuex 状态 vue-cli 命令行 vue vue vue-rou ...
- linux快速安装mysql教程
#安装mysql服务器:yum install mysql-server #设置开机启动chkconfig mysqld on#现在启动服务service mysqld start #设置root初始 ...