Java Timer(定时器)

Posted 86上山了、

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java Timer(定时器)相关的知识,希望对你有一定的参考价值。

概述:

Timer是一种定时器工具,用来在一个后台线程计划执行指定任务。它可以安排任务“执行一次”或者定期“执行多次”。                 
 然而在实际的开发过程当中,经常需要一些周期性的操作,比如每5分钟执行某一操作等。
 对于这样的操作最方便、高效的实现方式就是使用java.util.Timer工具类。

方法摘要:

schedule(TimerTask task, Date time) // 安排在 "指定的时间" 执行 指定的任务。(只执行一次)
schedule(TimerTask task,long delay) // 安排在指定延迟后执行指定的任务
schedule(TimerTask task, Date firstTime , long period) // 安排指定的任务在 "指定的时间 " 开始进行 "重复" 的固定延迟执行
schedule(TimerTask task,long delay,long period)// 安排指定的任务指定的延迟后开始进行重复的固定延迟执行.
scheduleAtFixedRate(TimerTask task,Date firstTime,long period)// 安排指定的任务在指定的时间开始进行重复的固定速率执行.
scheduleAtFixedRate(TimerTask task,long delay,long period)//安排指定的任务在指定的延迟后开始进行重复的固定速率执行.
Timer.cancal()// 终止此计时器,丢弃所有当前已安排的任务。
Timer.purge()// 从此计时器的任务队列中移除所有已取消的任务。
TimerTask.cancal()// 把当前任务取消

固定延迟:意味着执行将在最后一次执行开始后的一段时间内开始,即使它被延迟(因此它本身被延迟)。也就是说任务的 下一次执行时间 是相对于 上一次实际执行完成的时间点 ,因此执行时间会不断延后

固定频率:意味着每次执行都将遵守初始计划,无论之前的执行是否被延迟。也就是说任务的 下一次执行时间 是相对于 上一次开始执行的时间点 ,因此执行时间不会延后

关于这两种调度方式,让我们看看如何使用它们:

为了使用固定延迟调度,schedule()方法还有两个重载,每个重载都使用一个额外的参数来表示以毫秒为单位的周期性。为什么两次重载?因为仍然有可能在某个时刻或某个延迟之后开始执行任务。

至于固定频率调度,我们有两个scheduleAtFixedRate()方法,它们的周期也是以毫秒为单位的。同样,我们有一种方法可以在给定的日期和时间启动任务,还有一种方法可以在给定的延迟后启动任务。

注意一点:如果一个任务的执行时间超过了执行周期,那么无论我们使用固定延迟还是固定速率,它都会延迟整个执行链。(固定速率会连续执行,固定延迟会等待延迟再执行)

具体代码

schedule(TimerTask task, Date time)

/**
 * @PROJECT_NAME: demo
 * @DESCRIPTION: 指定时间执行
 */
public class TimerDemo 
    public static void main(String[] args) 
        Calendar ca = Calendar.getInstance();
        System.out.println(ca.getTime());
        ca.set(Calendar.SECOND, ca.get(Calendar.SECOND) + 5);
        new Timer().schedule(new TimerTask() 
            @Override
            public void run() 
                System.out.println(new Date(scheduledExecutionTime());
            
        , ca.getTime());
    

schedule(TimerTask task,long delay)

/**
 * @PROJECT_NAME: demo
 * @DESCRIPTION: 延迟指定时间后执行
 */
public class DelayDemo 
    public static void main(String[] args) 
        System.out.println(new Date());
        new Timer().schedule(new TimerTask() 
            @Override
            public void run() 
                System.out.println(new Date(scheduledExecutionTime());
            
        , 2000);
    

schedule(TimerTask task, Date firstTime, long period)

/**
 * @PROJECT_NAME: demo
 * @DESCRIPTION: 安排指定的任务在 "指定的时间 " 开始进行 "重复" 的固定延迟执行
 */
public class FirstAndPeriodDemo 
    public static void main(String[] args) 
        Calendar ca = Calendar.getInstance();
        System.out.println(ca.getTime());
        ca.set(Calendar.SECOND, ca.get(Calendar.SECOND) + 2);
        new Timer().schedule(new TimerTask() 
            @Override
            public void run() 
                try 
                    Thread.sleep(3000);
                 catch (InterruptedException e) 
                    e.printStackTrace();
                
                System.out.println(new Date(scheduledExecutionTime()));
            
        , ca.getTime(),2000);
    

第一次任务延迟了2s,然后之后因为实现线程执行时间为3s,所以在任务结束时在开始下一次任务。

schedule(TimerTask task,long delay,long period)


/**
 * @PROJECT_NAME: demo
 * @DESCRIPTION: 安排指定的任务在“指定的延迟”后开始进行“重复”的固定延迟执行
 */
public class DelayAndPeriodDemo 
    public static void main(String[] args) 
        System.out.println(new Date());
        new Timer().schedule(new TimerTask() 
            @Override
            public void run() 
                try 
                    Thread.sleep(3000);
                 catch (InterruptedException e) 
                    e.printStackTrace();
                
                System.out.println(new Date(scheduledExecutionTime()));
            
        , 1000,2000);
    

scheduleAtFixedRate(TimerTask task,Date firstTime,long period)

/**
 * @PROJECT_NAME: demo
 * @DESCRIPTION:
 */
public class FixAndFirstDemo 
    public static void main(String[] args) 
        System.out.println(new Date());
        new Timer().scheduleAtFixedRate(new TimerTask() 
            @Override
            public void run() 
                try 
                    Thread.sleep(3000);
                 catch (InterruptedException e) 
                    e.printStackTrace();
                
                System.out.println(new Date(scheduledExecutionTime()));
            
        , 1000, 2000);
    

按照固定速率执行。

但是,这儿引出了另外一个问题。既然 Timer 内部是单线程实现的,在执行间隔为2秒、任务实际执行为3秒的情况下, scheduleAtFixedRate 是如何做到2秒输出一次的呢?

【特别注意】

这儿其实是一个障眼法。需要重点关注的是,打印方法输出的值是通过调用 scheduledExecutionTime() 来生成的,而这个方法并不一定是任务真实执行的时间,而是当前任务应该执行的时间。
源码理解

Java Timer和TimerTask的使用

如果要执行一些简单的定时器任务,无需做复杂的控制,也无须保存状态,可以考虑使用JDK入门级的定时器Timer来执行重复任务。

JDK中,定时器任务的执行需要两个基本的类:

java.util.Timer;java.util.TimerTask;

运行一个定时任务基本步骤如下:

1、建立一个要执行的任务TimerTask;

2、创建一个Timer实例,通过Timer提供的schedule()方法,将TimerTask加入到定时器Timer中,同时设置执行的规则即可;

Timer中的schedule()有多种重载方法,以适应不同的情况:

schedule(TimerTask task, Date time):安排在指定时间执行指定任务;

schedule(TimerTask task, Date firsttime, Long period):安排指定的任务在指定时间指定周期重复执行;

schedule(TimerTask task, Long delay):安排在指定延迟后执行指定任务;

schedule(TimerTask task, Long delay, Long period):安排指定的任务从指定的延迟后开始重复的固定延迟执行;

 

示例如下:

 

import java.util.Timer; import java.util.TimerTask;

public class Test {  class TestTimerTask extends TimerTask{   private int i = 1;   @Override   public void run() {    System.out.println("定时器第"+i+"次执行!");    i += 1;       }     }  public static void main(String[] args) {   Test test = new Test();   Timer timer = new Timer();   timer.schedule(test.new TestTimerTask(), 3000, 2000);  } }

 

以上是关于Java Timer(定时器)的主要内容,如果未能解决你的问题,请参考以下文章

java 怎么写定时任务

java之定时器任务Timer用法

Java的定时调度

Java中的定时器Timer

Java Timer定时器原理

Java 如何实现这样的定时任务