定时任务就是在指定时间执行程序,或周期性执行计划任务。Java中实现定时任务的方法有很多,本文从从JDK自带的一些方法来实现定时任务的需求。

一、Timer和TimerTask

   Timer和TimerTask可以作为线程实现的第三种方式(前两种详见《Java多线程基础》),JDK1.5之后定时任务推荐使用ScheduledThreadPoolExecutor。

1、快速入门

   Timer运行在后台,可以执行任务一次,或定期执行任务。TimerTask类继承了Runnable接口,因此具备多线程的能力。一个Timer可以调度任意多个TimerTask,所有任务都存储在一个队列中顺序执行,如果需要多个TimerTask并发执行,则需要创建两个多个Timer。

  一个简单使用Timer的例子如下:

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask; public class TimerTest {
//被执行的任务必须继承TimerTask,并且实现run方法
static class MyTimerTask1 extends TimerTask {
public void run() {
System.out.println("爆炸!!!");
}
}
public static void main(String[] args) throws ParseException {
Timer timer = new Timer();
//1、设定两秒后执行任务
//timer.scheduleAtFixedRate(new MyTimerTask1(), 2000,1000);
//2、设定任务在执行时间执行,本例设定时间13:57:00
SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
Date time = dateFormatter.parse("2014/02/11 14:40:00");
timer.schedule(new MyTimerTask1(), time);
}
}

2、schedule与scheduleAtFixedRate使用方法

   schedule(TimerTask task, long delay, long period)   --指定任务执行延迟时间

   schedule(TimerTask task, Date time, long period)    --指定任务执行时刻

   scheduleAtFixedRate(TimerTask task, long delay, long period)

   scheduleAtFixedRate(TimerTask task, Date firstTime, long period)

3、schedule与scheduleAtFixedRate区别

   1) schedule:

   ① 注重任务执行的平滑度,也就是说任务队列中某个任务执行延迟了某个时间,接下来的其余任务都会延迟相同时间,来最大限度的保证任务与任务之间的时间间隔的完整性;

   ② 当程序指定开始时刻(Date time)小于当前系统时刻时,会立即执行一次任务,之后的任务开始执行时间以当前时刻为标准,结合时间间隔计算得到;

   例:计划任务程序指定从2014/02/11 18:00:00开始每隔3分钟执行一次任务。如果该程序在18:00:00之前运行,则计划任务程序分别会在18:00:00、18:03:00、18:06:00...等时间点执行任务;如果该程序在18:00:00之后运行,如在18:07:00时刻开始运行程序,计划任务程序判断指定开始执行时刻18:00:00小于当前系统时刻,于是立即执行一次任务,接下来任务时间时刻分别为18:10:00、18:13:00、18:16:00...;而当使用scheduleAtFixedRate执行计划任务时,无论计划任务程序在什么时候运行,所有任务执行的次数都按照原计划,不会因为程序执行时刻的早晚而改变。而当程序运行时刻比计划任务计划首次执行时间晚时,如同样在18:07:00时刻开始执行程序,则计划任务程序会立马计算程序执行时刻晚于指定时刻,会立即执行(18:07:00-18:00:00)/3+1=3次任务(代表18:00:00、18:03:00和18:06:00三个时刻执行的任务),接下来任务执行时刻是18:09:00、18:12:00等。

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask; public class TimerRateFix {
public static void main(String[] args) throws ParseException {
final SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
Date startDate = dateFormatter.parse("2014/02/11 18:00:00");
Timer timer = new Timer();
timer.schedule(new TimerTask(){
public void run()
{
System.out.println("执行任务,当前时刻:" + dateFormatter.format(new Date()));
}
},startDate,3*60*1000);
}
}

   ③ 当执行任务的时间间隔t1大于周期间隔t2时,下一次任务执行时间点相对于上一次任务实际执行完成的时间点,每个任务的执行时间会延后,第n个计划任务的实际执行时间比预计要延后(t1-t2)*n个时间单位。

   例:计划任务程序指定从2014/02/11 18:00:00开始每隔5秒执行一次任务,每次任务执行时间为6秒。当程序在18:00:00之前执行时,schedule分别会在18:00:00、18:00:06、18:00:12...等时间点执行计划任务,每隔时间点间隔6秒。原因是根据计划,第一个计划任务应会在18:00:00执行,第二个计划任务应会在18:00:05执行,而在18:00:05时间点,第一个任务才执行了5秒,还需要1秒才执行结束,因此第二个任务不能执行,于是等待1秒后在18:00:06时刻执行,之后每个任务均如此,均比原定执行时刻有延迟,每个任务时间间隔为6秒。当使用scheduleAtFixedRate执行计划任务时,第一个计划任务在18:00:00时刻执行,第二个会根据计划在18:00:05执行,第三个会在18:00:10执行,每个任务执行时间间隔为5秒,详细执行情况如下图所示

图1 schedule与scheduleAtFixedRate任务执行区别

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
public class TimerRateTest {
public static void main(String[] args) throws ParseException {
final SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
Timer timer = new Timer();
Date time = dateFormatter.parse("2014/02/11 18:00:00");
//假设程序在2014/02/11 18:00:00之前启动
//1、使用scheduleAtFixedRate,每个计划任务执行时间点严格为18:00:00、18:00:05、18:00:10...,当任务执行时间大于时间间隔时可能会有并发情况
//2、使用schedule,每个计划任务执行时间点根据上一个任务执行结束时间及时间间隔来计算
// 当任务执行时间t1>时间间隔t2时,第N个计划任务执行时间点延迟为(t1-t2)*N,执行时间点为18:00:00+t2*(N-1)+(t1-t2)*N
// 当任务执行时间t1<=时间间隔t2时,第N个计划任务执行时间点无延迟,执行时间为原计划
timer.scheduleAtFixedRate(new TimerTask(){
public void run() {
try {
//每个计划任务执行时间为6秒
Thread.sleep(6000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("结束当前任务,当前时间:"+ dateFormatter.format(new Date()));
}
},time,5000); //计划任务执行时间间隔为5秒
}
}

   2) scheduleAtFixedRate:

   ① 注重任务执行的频度,也就是说计划任务程序开始执行,每隔任务执行的时间点就已经确定,并不会因为某个任务的延迟而延迟执行其他任务,可以保证任务执行的时间效率;

   ② 当程序指定开始时刻(Date firstTime)小于当前系统时刻时,会立即执行任务,执行次数为(当前系统时刻-指定开始时刻)/时间间隔,之后的任务开始执行时刻与当前系统时刻无关,仍按照程序指定开始时刻根据时间间隔计算得到;

   ③ 当执行任务的时间间隔t1大于周期间隔t2时,下一次任务执行时间点还是按照原定计划不变,因此这种情况,有部分时间断可能有多个任务并发执行

4、终止Timer线程

   1) 调用Timer.cancle()方法。可以在程序任何地方调用,甚至在TimerTask中的run方法中调用;

   2) 创建Timer时定义位daemon守护线程(有关守护线程见《Java守护线程》),使用new Timer(true)语句;

   3) 设置Timer对象为null,其会自动终止;

   4) 调用System.exit方法,整个程序终止。

5、Timer线程的缺点

   1) Timer线程不会捕获异常,所以TimerTask抛出的未检查的异常会终止timer线程。如果Timer线程中存在多个计划任务,其中一个计划任务抛出未检查的异常,则会引起整个Timer线程结束,从而导致其他计划任务无法得到继续执行。  

   2) Timer线程时基于绝对时间(如:2014/02/14 16:06:00),因此计划任务对系统的时间的改变是敏感的。

   3) Timer是单线程,如果某个任务很耗时,可能会影响其他计划任务的执行。

   因此,JDK1.5以上建议使用ScheduledThreadPoolExecutor来代替Timer执行计划任务。   

二、ScheduledThreadPoolExecutor

  ScheduledThreadPoolExecutor是JDK1.5以后推出的类,用于实现定时、重复执行的功能,官方文档解释要优于Timer。

1、构造方法   

   1) ScheduledThreadPoolExecutor(int corePoolSize) 使用给定核心池大小创建一个新定定时线程池

   2) ScheduledThreadPoolExecutor(int corePoolSize, ThreadFactorythreadFactory) 使用给定的初始参数创建一个新对象,可提供线程创建工厂

private final static ScheduledThreadPoolExecutor schedual = new ScheduledThreadPoolExecutor(1, new ThreadFactory() {
private AtomicInteger atoInteger = new AtomicInteger(0);
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
t.setName("xxx-Thread "+ atoInteger.getAndIncrement());
return t;
}
});

2、调度方法

   1) schedule(Callable callable, long delay, TimeUnit unit);  延迟delay时间后开始执行callable

   2) scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit);  延迟initialDelay时间后开始执行command,并且按照period时间周期性重复调用,当任务执行时间大于间隔时间时,之后的任务都会延迟,此时与Timer中的schedule方法类似

   3) scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit);  延迟initialDelay时间后开始执行command,并且按照period时间周期性重复调用,这里的间隔时间delay是等上一个任务完全执行完毕才开始计算,与Timer中scheduleAtFixedRate情况不同。

图2 ScheduledThreadPoolExecutor.scheduleWithFixedDelay与Timer.scheduleAtFixedRate任务执行区别

3、与Timer相比,优点有:

   1) ScheduledThreadPoolExecutor线程会捕获任务重的异常,即使多个计划任务中存在某几个计划任务为捕获异常的情况,也不会影响ScheduledThreadPoolExecutor总线程的工作,不会影响其他计划任务的继续执行。

   2) ScheduledThreadPoolExecutor是基于相对时间的,对系统时间的改变不敏感,但是如果执行某一绝对时间(如2014/02/14 17:13:06)执行任务,可能不好执行,此时可使用Timer。

   3) ScheduledThreadPoolExecutor是线程池,如任务数过多或某些任务执行时间较长,可自动分配更多的线程来执行计划任务。

   总之,JDK1.5之后,计划任务建议使用ScheduledThreadPoolExecutor。

Java定时任务Timer、TimerTask与ScheduledThreadPoolExecutor详解的更多相关文章

  1. java线程池的使用与详解

    java线程池的使用与详解 [转载]本文转载自两篇博文:  1.Java并发编程:线程池的使用:http://www.cnblogs.com/dolphin0520/p/3932921.html   ...

  2. java的集合框架最全详解

    java的集合框架最全详解(图) 前言:数据结构对程序设计有着深远的影响,在面向过程的C语言中,数据库结构用struct来描述,而在面向对象的编程中,数据结构是用类来描述的,并且包含有对该数据结构操作 ...

  3. Java学习-007-Log4J 日志记录配置文件详解及实例源代码

    此文主要讲述在初学 Java 时,常用的 Log4J 日志记录配置文件详解及实例源代码整理.希望能对初学 Java 编程的亲们有所帮助.若有不足之处,敬请大神指正,不胜感激!源代码测试通过日期为:20 ...

  4. 【转】Java魔法堂:String.format详解

    Java魔法堂:String.format详解     目录     一.前言    二.重载方法     三.占位符     四.对字符.字符串进行格式化     五.对整数进行格式化     六. ...

  5. Java之Static静态修饰符详解

    Java之Static静态修饰符详解 Java之Static静态修饰符详解 一.特点 1.随着类的加载而加载,随着类的消失而消失,生命周期最长 2.优先于对象存在 3.被所有类的对象共享 4.可以直接 ...

  6. Java 反射 设计模式 动态代理机制详解 [ 转载 ]

    Java 反射 设计模式 动态代理机制详解 [ 转载 ] @author 亦山 原文链接:http://blog.csdn.net/luanlouis/article/details/24589193 ...

  7. Java线程创建形式 Thread构造详解 多线程中篇(五)

    Thread作为线程的抽象,Thread的实例用于描述线程,对线程的操纵,就是对Thread实例对象的管理与控制. 创建一个线程这个问题,也就转换为如何构造一个正确的Thread对象. 构造方法列表 ...

  8. (7)Java数据结构--集合map,set,list详解

    MAP,SET,LIST,等JAVA中集合解析(了解) - clam_clam的专栏 - CSDN博---有颜色, http://blog.csdn.net/clam_clam/article/det ...

  9. 牛客网 Java 工程师能力评估 20 题 - 详解

    牛客网 Java 工程师能力评估 20 题 - 详解 不知在看博客的你是否知道 牛客网,不知道就太落后了,分享给你 : 牛客网 此 20 题,绝对不只是 20 题! 免责声明:本博客为学习笔记,如有侵 ...

随机推荐

  1. NV SDK 9.5, 10 and 11

    NVIDIA SDK 10   Overview This all-new collection of DirectX 10 and OpenGL code samples teaches devel ...

  2. [ZZ] D3D中的模板缓存(3)

    http://www.cppblog.com/lovedday/archive/2008/03/25/45334.html http://www.cppblog.com/lovedday/ D3D中的 ...

  3. PHP 设计模式 笔记与总结(7)适配器模式

    ① 适配器模式可以将截然不同的函数接口封装成统一的 API ② 实际应用举例:PHP 的数据库操作有 mysql,mysqli,pdo 三种,可以用适配器模式统一成一致.类似的场景还有 cache 适 ...

  4. mac 下 word 2011 使用笔记

    1. 全屏预览,最大限度减少干扰 点击左下角焦点视图图标进入焦点视图. 调整为页面宽度或单页,点击顶部右侧百分比调整. 2.无格式粘贴 option + shift + command + v 3.无 ...

  5. CentOS安装TortoiseSVN svn 客户端

    CentOS安装TortoiseSVN svn 客户端   一.CentOS安装TortoiseSVN yum install -y subversion 二.SVN客户端命令 1.查看帮助 命令:s ...

  6. Nginx模块fastcgi_cache的几个注意点

    fastcgi响应http请求的结果中,响应头包括Expires、Cache-Control、Set-Cookie三个,都会可能不被cache. thinkphp3.0禁止session自动启动 co ...

  7. 【php学习】图片操作

    前两天要对一张图片进行处理,其实很简单,就是在图片上加上字符串,一个图片而已,但是自己如同得了短暂性失忆似的,图片操作的函数一个都想不起来.所以就抽空整理了一下图片操作函数. 图片处理三步走: 创建画 ...

  8. dom paser

    dom paser /** * */ package ec.utils; import java.io.BufferedInputStream; import java.io.ByteArrayInp ...

  9. Jquery元素选取、常用方法;js只能获取内联样式,jquery内联内嵌都可以获取到;字符串.trim();去字符串前后空格

    一:常用的选择器: 基本选择器 $("#myDiv") //匹配唯一的具有此id值的元素 $("div") //匹配指定名称的所有元素 $(".myC ...

  10. Qt工具知多少(一目了然)

    一级题目: Qt Designer — 所见即所得的界面设计工具, 可以用拖拽的方式将控件排布在界面上,支持layout, 支持signal/slot编辑. 生成的文件保存为ui格式, ui是xml格 ...