`

Java:利用java Timer类实现定时执行任务的功能

阅读更多
Java:利用java Timer类实现定时执行任务的功能

一、概述

在java中实现定时执行任务的功能,主要用到两个类,Timer和TimerTask类。其中Timer是用来在一个后台线程按指定的计划来执行指定的任务。
TimerTask一个抽象类,它的子类代表一个可以被Timer计划的任务,具体要执行的代码写在TimerTask需要被实现的run方法中。

二、先看一个最简单的例子

我们通过代码来说明

复制代码
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

public class TimerDemo {
    public static String getCurrentTime() {
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return sdf.format(date);
    }

    public static void main(String[] args) throws InterruptedException {
        System.out.println("main start:"+getCurrentTime());
        startTimer();
        Thread.sleep(1000*5); //休眠5秒
        System.out.println("main   end:"+getCurrentTime());
    }

    public static void startTimer(){
        TimerTask task = new TimerTask() {
            @Override
            public void run() {
                System.out.println("task   run:"+getCurrentTime());
            }
        };
        Timer timer = new Timer();
        timer.schedule(task, 0);
    }
}
复制代码
  为了便于通过打印观察信息,我们在main方法中加了些打印信息,并调用Thread.sleep让主线程休眠一下。另外在类中增加了一个获取当前日期的getCurrentTime方法。

      上面的代码,在startTimer方法中,先创建了一个TimerTask对象(将要被定时器执行的任务),然后创建了一个Timer对象,然后调用Timer类的schedule方法。Timer类有多个带不同参数的schedule方法。这里用到的是:

  public void schedule(TimerTask task, long delay)

  该方法的含义是,表示定时器将延迟delay(毫秒)时间后,执行task任务。如果delay为负数或0,则任务会被立即进行。而且是一次性的执行任务,后续不会重复(或定时)执行该任务。

      对于Timer类,还提供一个同样功能的方法,如下:

  public void schedule(TimerTask task, Date time)

     该方法与上面方法的区别是,上面方法是指定延期一段时间执行,这个方法是指定在某个具体的时间点执行。注意,如果系统的当前时间已经超过了参数time指定的时间,该任务会被立即执行。

当运行上面代码时,我们发现程序立即打印类似如下的2条信息:
main start:2016-01-13 22:23:18
task   run:2016-01-13 22:23:18

因为我们这里给schedule方法传递的delay参数值为0,所以任务会被立即执行,所以两个语句打印出来的时间是一样的,这是应该的。大家可以自己改变传入的delay值来看输出信息的变化。再过大约5秒(即sleep的时间)后,继续打印了1条信息:

main   end:2016-01-13 22:23:23

打印信息的时间与上面语句差了5秒,与sleep设置的一致,也是很合理的。

但我们会发现一个很有趣的现象,会发现该进程不会退出,这时main主线程已经结束了,这说明定时器把任务完成后,即使后面没有待等待执行的任务了,定时器中创建的后台线程也不会立即退出。查看了相关的java doc文档,解释说定时器线程不会主动退出,需要等待垃圾回收,但java的待垃圾回收是无法通过代码自己控制的,而是由虚拟机控制的。

研究了下,发现在创建Timer对象,及执行Timer timer = new Timer(); 语句时,定时器线程就会被创建。也就是说即使上面代码没有timer.schedule(task, 0);这个语句,程序也不会退出。感觉这个挺不合理的。再次研究了下Timer类的源代码,发现其还有一个带布尔参数的构造函数:

public Timer(boolean isDaemon)

从参数名就可以看出,如果参数值为true时,则Timer创建的定时器线程为守护线程。守护线程的含义是,当java进程中所有的工作线程都退出后,守护线程就自动退出了。

这时我们只要把上面例子中的创建Timer对象的代码改为:Timer timer = new Timer(true);

发现运行程序后,等main线程(main线程不是守护线程,是工作线程)结束后,程序会退出,也就是说定时器线程也退出了,说明加上参数true后,创建的它是守护线程了。

   但问题是,在真正的应用场景中,有很多工作线程在运行,程序不会随便退出。那如果要想定时器能立即退出或关闭,该怎么办呢?这个我们下面介绍。

三、定时器的退出

  Timer类提供了一个cancel方法可以取消定时器。调用cancel方法会终止此计时器,丢弃所有当前已安排的任务。这不会干扰当前正在执行的任务(如果存在)。一旦终止了计时器,那么它的执行线程也会终止,并且无法根据它安排更多的任务。
  注意,在此计时器调用的计时器任务的 run 方法内调用此方法,就可以绝对确保正在执行的任务是此计时器所执行的最后一个任务。可以重复调用此方法;但是第二次和后续调用无效。

    我们再看一个例子代码:

复制代码
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

public class TimerDemo {
    public static String getCurrentTime() {
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return sdf.format(date);
    }

    public static void main(String[] args) throws InterruptedException {
        System.out.println("main start:"+getCurrentTime());
        Timer timer = startTimer();
        Thread.sleep(1000*5); //休眠5秒
        System.out.println("main   end:"+getCurrentTime());
        timer.cancel();
    }

    public static Timer startTimer(){
        TimerTask task = new TimerTask() {
            @Override
            public void run() {
                System.out.println("task   run:"+getCurrentTime());
            }
        };
        Timer timer = new Timer();
        timer.schedule(task, 0);
        return timer;
    }
}
复制代码
运行程序,跟上面一个例子的输出情况完全一样。区别是,当main方法结束后。进程会主动退出,也就是说定时器线程已经关闭了。
因为我们在main方法中调用了cancel方法。 注意,如果不是在TimerTask的run方法中调用cancel方法一定要注意,一定要确保希望执行的任务已经开始执行或执行完毕,否则如果任务还未开始执行。就调用cancel,则所有任务都不会被执行了。比如上面的代码,

比如上面的代码,如果我们不在main方法中调用cancel方法,而是在startTimer方法中 timer.schedule(task, 0); 语句后加上timer.cancel();语句,运行后会发现,定时器任务不会被执行,因为还未来得及执行就被取消中止了。

四、定时执行任务

    上面的例子,我们介绍的是一次性任务,也就是定时器时间到了,执行完任务,后面不会再重复执行。在实际的应用中,有很多场景需要定时重复的执行同一个任务。这也分两种情况,一是每隔一段时间就执行任务,二是每天(或每周、每月等)的固定某个(或某几个)时间点来执行任务。

    我们先来看第一种情况,实现每隔10秒执行同一任务的例子。代码如下:

复制代码
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

public class TimerDemo {
    public static String getCurrentTime() {
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return sdf.format(date);
    }

    public static void main(String[] args) throws InterruptedException {
        System.out.println("main start:"+getCurrentTime());
        startTimer();
    }

    public static void startTimer(){
        TimerTask task = new TimerTask() {
            @Override
            public void run() {
                System.out.println("task   run:"+getCurrentTime());
                try {
                    Thread.sleep(1000*3);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        Timer timer = new Timer();
        timer.schedule(task, 1000*5,1000*10);
    }
}
复制代码
执行上述程序,输出信息如下(因为定时器没有停止,重复执行任务,会不断输出,这里只拷贝了前面的一些输出)

复制代码
main start:2016-01-14 08:41:14
task   run:2016-01-14 08:41:19
task   run:2016-01-14 08:41:29
task   run:2016-01-14 08:41:39
task   run:2016-01-14 08:41:49
task   run:2016-01-14 08:42:00
task   run:2016-01-14 08:42:10
task   run:2016-01-14 08:42:20
task   run:2016-01-14 08:42:30
task   run:2016-01-14 08:42:40
复制代码
在上面的代码中,我们调用了 timer.schedule(task, 1000*5,1000*10); 这个含义是该任务延迟5秒后执行,然后会每隔10秒重复执行。我们观察输出信息中打印的时间,是与预期一样的。 另外可以看出,间隔是以任务开始执行时间为起点算的,也就是并不是任务执行完成后再等待10秒。

Timer类有两个方法可以实现这样的功能,如下:
public void schedule(TimerTask task, long delay, long period)

public void schedule(TimerTask task, Date firstTime, long period)

我们上面代码用的是第一个方法。两个方法区别在于第一次执行的时间,第一个方法是在指定延期一段时间(单位为毫秒)后执行;第二个方法是在指定的时间点执行。

这时我们考虑如下场景,如果某个任务的执行耗时超过了下次等待时间,会出现什么情况呢? 我们还是通过代码来看:

复制代码
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

public class TimerDemo {
    public static String getCurrentTime() {
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return sdf.format(date);
    }

    public static void main(String[] args) throws InterruptedException {
        System.out.println("main start:"+getCurrentTime());
        startTimer();
    }

    public static void startTimer(){
        TimerTask task = new TimerTask() {
            @Override
            public void run() {
                System.out.println("task begin:"+getCurrentTime());
                try {
                    Thread.sleep(1000*10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("task   end:"+getCurrentTime());
            }
        };
        Timer timer = new Timer();
        timer.schedule(task, 1000*5,1000*5);
    }
}
复制代码
与前面代码相比,我们只改了2处代码和修改了下打印,一是将run方法中的sleep改为了10秒,二是将任务的执行周期改为5秒。也就说任务的执行耗时超过了任务重复执行的间隔。运行程序,前面的输出如下:

复制代码
main start:2016-01-14 09:03:51
task begin:2016-01-14 09:03:56
task   end:2016-01-14 09:04:06
task begin:2016-01-14 09:04:06
task   end:2016-01-14 09:04:16
task begin:2016-01-14 09:04:16
task   end:2016-01-14 09:04:26
task begin:2016-01-14 09:04:26
task   end:2016-01-14 09:04:36
task begin:2016-01-14 09:04:36
task   end:2016-01-14 09:04:46
task begin:2016-01-14 09:04:46
task   end:2016-01-14 09:04:56
复制代码
可以看出,每个任务执行完成后,会立即执行下一个任务。因为从任务开始执行到任务完成的耗时已经超过了任务重复的间隔时间,所以会重复执行。

五、定时执行任务(重复固定时间点执行)

我们来实现这样一个功能,每天的凌晨1点定时执行一个任务,这在很多系统中都有这种功能,比如在这个任务中完成数据备份、数据统计等耗时、耗资源较多的任务。代码如下:

复制代码
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

public class TimerDemo {
    public static String getCurrentTime() {
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return sdf.format(date);
    }

    public static void main(String[] args) throws InterruptedException {
        System.out.println("main start:" + getCurrentTime());
        startTimer();
    }

    public static void startTimer() {
        TimerTask task = new TimerTask() {
            @Override
            public void run() {
                System.out.println("task begin:" + getCurrentTime());
                try {
                    Thread.sleep(1000 * 20);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("task   end:" + getCurrentTime());
            }
        };
        Timer timer = new Timer();
        timer.schedule(task, buildTime(), 1000 * 60 * 60 * 24);
    }

    private static Date buildTime() {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.HOUR_OF_DAY, 1);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        Date time = calendar.getTime();
        if (time.before(new Date())) {
            //若果当前时间已经是凌晨1点后,需要往后加1天,否则任务会立即执行。
            //很多系统往往系统启动时就需要立即执行一次任务,但下面又需要每天凌晨1点执行,怎么办呢?
            //很简单,就在系统初始化话时单独执行一次任务(不需要用定时器,只是执行那段任务的代码)
            time = addDay(time, 1);
        }
        return time;
    }

    private static Date addDay(Date date, int days) {
        Calendar startDT = Calendar.getInstance();
        startDT.setTime(date);
        startDT.add(Calendar.DAY_OF_MONTH, days);
        return startDT.getTime();
    }

}


url:http://www.cnblogs.com/51kata/p/5128745.html
分享到:
评论

相关推荐

    Java定时任务:利用java Timer类实现定时执行任务的功能

    【Java定时任务:利用java Timer类实现定时执行任务的功能】 在Java编程中,有时我们需要在特定的时间点或者按照预设的间隔执行某些任务,这就需要用到定时任务。Java提供了`java.util.Timer`类来帮助我们实现这个...

    java定时任务,每天定时执行任务

    Java 定时任务是指在 Java 语言中实现的定时执行任务的机制,通过使用 Timer 和 TimerTask 两个类,可以实现定时执行任务的功能。在这个例子中,我们将实现每天定时执行任务的功能,具体来说,就是在每天的凌晨 2 点...

    java轻松实现—定时任务

    在Java中,我们可以利用`java.util.Timer`类和`java.util.TimerTask`类来实现简单的定时任务,但这种实现方式存在线程安全问题。在Web应用中,我们可以利用Servlet容器提供的特性来更优雅地处理定时任务,这就是描述...

    java.util.timer实现的简单定时任务

    Java.util.Timer类是Java标准库提供的一种简单但功能有限的定时任务执行机制。它允许开发者在指定的时间间隔或特定时间点执行任务,非常适合处理一次性或周期性的后台操作。本篇文章将深入探讨如何使用Timer和...

    java 定时执行任务

    `Timer`类是Java早期提供的定时任务实现,它允许我们创建一个定时器对象,然后调度`TimerTask`任务来执行。以下是如何使用`Timer`和`TimerTask`的基本步骤: ```java import java.util.*; class TimerTaskDemo ...

    Java定时执行某个任务

    总结起来,Java提供了`Timer`和`ScheduledExecutorService`两种方式来实现定时执行任务。`Timer`适合简单的定时任务,而`ScheduledExecutorService`更适合复杂的需求,如多线程环境和高并发场景。选择哪种方式取决于...

    Java里timer执行定时任务

    在Java中,`java.util.Timer` 类提供了创建和管理定时任务的功能。如果需要在特定时间之后执行某个任务,可以利用 `Timer` 类的 `schedule()` 方法。此方法接受一个实现了 `TimerTask` 接口的实例以及一个表示延迟...

    java定时任务调度之Timer 简单示例

    Java定时任务调度是Java应用程序中常见的一种功能,用于在特定时间执行特定任务,例如定期备份、数据清理等。`Timer`类是Java中用于实现定时任务调度的一个基础工具,它位于`java.util`包中。在本文中,我们将深入...

    java Timer 定时每天凌晨1点执行任务

    在Java中,Timer类是一个非常有用的工具类,它可以帮助我们实现定时任务的执行。在本篇文章中,我们将学习如何使用Java Timer来实现每天凌晨1点执行任务的功能。 首先,让我们了解一下 Timer类的基本概念。Timer类...

    Java定时执行任务的三种方法

    `java.util.Timer`类是最基础的定时任务工具,它允许我们创建一个Timer对象并安排任务执行。在创建Timer实例后,通过`schedule`方法可以设置定时任务。例如: ```java Timer timer = new Timer(); timer....

    java定时任务的实现方式

    本文将详细介绍两种常用的Java定时任务实现方式:Timer类和Spring框架的Quartz调度器。 首先,第一种方式是使用Java内置的`Timer`类。`Timer`类提供了定时任务调度的功能,可以按照预设的时间间隔执行任务。在提供...

    java每天实现定点执行任务

    要完成这样的功能,我们通常会利用Java的定时任务框架,如`java.util.Timer`类、`java.util.concurrent.ScheduledExecutorService`或者更高级的Quartz库。以下将详细介绍如何使用这些方法来实现每日定时任务。 1. *...

    Quartz--JAVA定时任务\Java应用:Java调度任务和Spring Quartz (1)

    不过,`Timer`类的功能相对有限,无法精确地在特定时间点执行任务,比如设置每天特定时间执行的任务。 Quartz是一个强大且灵活的开源作业调度框架,能够弥补`Timer`的不足。Quartz允许开发者创建和管理作业(Job)...

    java定时器定时调用任务

    总结来说,Java定时器是通过`Timer`和`TimerTask`类实现的,它们提供了基础的定时任务调度功能。在Servlet环境中,我们可以利用监听器或Servlet的初始化方法来整合定时器。然而,对于更复杂的定时需求,建议使用`...

    JAVA项目服务器启动时自启动指定的Servlet,并定时执行任务

    在Servlet中实现定时任务,我们可以使用Java的定时框架如`java.util.Timer`或`ScheduledExecutorService`(推荐)。以下是一个使用`ScheduledExecutorService`的例子: ```java import java.util.concurrent....

    定时执行任务例子 绝对好用

    本示例介绍了一种使用Java的`Timer`类和`TimerTask`类来实现定时任务的方法,特别适用于J2EE环境。 ### 1. `Timer`类和`TimerTask`类 `Timer`类是Java的定时器,它可以安排在将来某一时间执行的任务。`TimerTask`...

    小码农的代码(四)----------JAVA中Timer定时器与Spring定时任务

    在Java编程语言中,`Timer`类和Spring框架的定时任务是两种常见的实现定时执行任务的方式。本篇文章将深入探讨这两个主题,旨在帮助初学者理解它们的工作原理以及如何在实际项目中应用。 首先,让我们来看一下Java...

    java定时执行多任务和quartz定时执行多任务

    Java定时执行多任务是软件开发中的常见需求,用于在特定时间点或按固定频率执行某项操作,例如数据同步、日志清理等。Java提供了一些内置的定时工具,如`java.util.Timer`和`java.util.concurrent....

    java写定时任务,定时任务、定时器详细示例

    在Java中,`java.util.Timer`类提供了调度定时任务的功能,而`java.util.TimerTask`则是执行这些任务的具体载体。两者结合,可以灵活地安排任务的执行时间、频率以及执行条件。 #### TimerTask类 `TimerTask`是一...

Global site tag (gtag.js) - Google Analytics