定时器Timer详细解析与举例

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
简介: 定时器java.util.Timer:功能是在指定的时间间隔内反复触发指定任务的定时器事件,主要用于定时性、周期性任务的触发。


1.1构造方法

Timer()**:**创建一个新的定时器。

Timer(boolean isDaemon)**:**创建一个新的定时器,true:该定时器关联的线程可以被指定作为守护线程运行。

Timer(String name):创建一个新的定时器,该定时器的关联线程具有指定的名称。

Timer(String name, boolean isDaemon)**:**创建一个新的定时器,该定时器的关联线程可以具有指定的名称,并且可能被指定作为守护线程运行。

1.2常用方法概要

①**void cancel()**

*功能:*终止此计时器,丢弃任何当前计划的任务。

*例如:*time.cancel();


②**int   purge()**

*功能:*从这个计时器的任务队列中移除所有已取消的任务。

*例如:*time. purge ();


③**void schedule(TimerTask task, Date time)**

  task- task to be scheduled.要调度的任务.

  time- time at which task is to be executed. 任务将要被调度的时间点

*功能:*在指定的时间点time上调度执行指定的任务,仅仅调度一次。

*例如:*

Calendar calendar = Calendar.getInstance();

calendar.set(Calendar.HOUR_OF_DAY, 15);

calendar.set(Calendar.MINUTE, 54);

calendar.set(Calendar.SECOND, 0);

Date time = calendar.getTime();

timer.schedule(task,time);

*说明:*任务task将会在当天的15:54:00时被调度一次。

*运行结果:*

2016-08-31 15:53:56

执行次数:0

2016-08-31 15:54:00


④**void     schedule(TimerTask task, long delay)**

  task- task to be scheduled. 要调度的任务.

  delay- delay in milliseconds before task is to be executed. 延迟等待delay(ms)

*功能:*调度一个task,延迟等待指定时间delay(毫秒ms)后开始进行调度,并且仅仅调度一次。

例如:*time*.schedule(task, 5000L);

*说明:*延迟5s=5000ms后调度任务task

*运行结果:*

2016-08-31 15:57:40

执行次数:0

2016-08-31 15:57:45


⑤**void     schedule(TimerTask task, Date firstTime, long period)**

   task -task to be scheduled.要调度的任务

   firstTime -First time at which task is to be executed. 第一次被调度的时间点

   period - timein milliseconds between successive task executions.每次调度完至       少等待时间

*功能:*调度一个task,在指定时间点firstTime开始调度,每次调度完后,最少等待period(毫秒ms)后才开始下次调度。重复调度多次。

*例如:*

Calendar calendar = Calendar.getInstance();

calendar.set(Calendar.HOUR_OF_DAY, 16);

calendar.set(Calendar.MINUTE, 15);

calendar.set(Calendar.SECOND, 0);

Date time = calendar.getTime();

timer.schedule(task,time,1000L);

*说明:*任务task在16:13:00开始调度,每次调度前最少等待1s

*运行结果:*

2016-08-31 16:14:25

执行次数:0

2016-08-31 16:15:00

执行次数:1

2016-08-31 16:15:01

执行次数:2

2016-08-31 16:15:02

执行次数:3

2016-08-31 16:15:03

执行次数:4

2016-08-31 16:15:04

取消5


⑥**void     schedule(TimerTask task, long delay, long period):**

   task - taskto be scheduled.要调度的任务

   delay - delayin milliseconds before task is to be executed. 第一次被调度延迟等待时间

   period - timein milliseconds between successive task executions. 每次调度完至少等待时间

*功能:*调度一个task,在延迟等待delay(毫秒ms)后开始调度,每次调度完后,最少等待period(毫秒ms)后才开始下次调度。重复调度多次。

*例如:*timer.schedule(task, 2000L,1000L);

*说明:*任务task延迟等待2s后开始调度,每次调度前最少等待1s

*运行结果:*

2016-08-31 15:39:55

执行次数:0

2016-08-31 15:39:57

执行次数:1

2016-08-31 15:39:58

执行次数:2

2016-08-31 15:39:59

执行次数:3

2016-08-31 15:40:00

执行次数:4

2016-08-31 15:40:01

取消5


⑦**void  scheduleAtFixedRate(TimerTask task, Date firstTime, long period)**

   task - task to be scheduled. 要调度的任务

   firstTime -First time at which task is to be executed. 第一次被调度的时间点

   period - timein milliseconds between successive task executions.每次调度完至       少等待时间

*功能:*调度一个task,在指定时间点firstTime开始调度,每次调度完后,按照指定频度period(ms)优先调用。重复调度多次。

*例如:*

Calendar calendar = Calendar.getInstance();

calendar.set(Calendar.HOUR_OF_DAY, 16);

calendar.set(Calendar.MINUTE, 15);

calendar.set(Calendar.SECOND, 0);

Date time = calendar.getTime();

timer.scheduleAtFixedRate(task,time,1000L);

*说明:*任务task在16:15:00开始调度,按照1s的频度进行调度

*运行结果:*

2016-08-31 16:15:45

执行次数:0

2016-08-31 16:16:00

执行次数:1

2016-08-31 16:16:01

执行次数:2

2016-08-31 16:16:02

执行次数:3

2016-08-31 16:16:03

执行次数:4

2016-08-31 16:16:04

取消5


⑧**void  scheduleAtFixedRate(TimerTask task, long delay, long period)**

   task - taskto be scheduled.要调度的任务

   delay - delayin milliseconds before task is to be executed. 第一次被调度延迟等待时间

   period - timein milliseconds between successive task executions.每次调度完至       少等待时间

*功能:*调度一个task,在指定时间点firstTime开始调度,每次调度完后,按照指定频度period(ms)优先调用。重复调度多次。

*例如:*

Calendar calendar = Calendar.getInstance();

calendar.set(Calendar.HOUR_OF_DAY, 16);

calendar.set(Calendar.MINUTE, 15);

calendar.set(Calendar.SECOND, 0);

Date time = calendar.getTime();

timer.scheduleAtFixedRate(task,time,1000L);

*说明:*任务task在16:15:00开始调度,按照1s的频度进行调度

*运行结果:*

2016-08-31 16:15:45

执行次数:0

2016-08-31 16:16:00

执行次数:1

2016-08-31 16:16:01

执行次数:2

2016-08-31 16:16:02

执行次数:3

2016-08-31 16:16:03

执行次数:4

2016-08-31 16:16:04

取消5

1.3 schedule和scheduleAtFixedRate的比较

schedule**方法:**"fixed-delay":如果上一次执行时间被delay了,随后的执行时间就按照上一次实际执行完成的时间点进行计算;

即:下一次的执行时间点=上一次程序执行完成的时间点+间隔时间

scheduleAtFixedRate**方法:**"fixed-rate":如果上一次执行时间delay了,随后的执行时间按照 上一次开始执行的时间点进行计算,并且为了"catch up"会多次执行任务,TimerTask中的执行体中需要考虑线程同步;

即:下一次的执行时间点**=上一次程序开始执行的时间点+间隔时间;并且如果前一个任务要执**行n秒,而当前任务已经开始执行,因此两个任务间存在重叠,需要考虑线程同步。

当执行任务的时间片大于周期间隔时,会发生什么呢?1). schedule方法:下一次执行时间相对于 上一次实际执行完成的时间点 ,因此执行时间会不断延后2). scheduleAtFixedRate方法:下一次执行时间相对于上一次开始的时间点 ,因此执行时间不会延后,存在并发性,**需要考虑线程同步**

测试实例

import java.util.Timer;

import java.util.TimerTask;

public**class**TimerTest {

static Timer timer = null;

public**staticvoid** main(String[] args) {

timer = new Timer();

   //延迟等待2s后,每间隔1s调度,1s间隔时间<执行时间2s

timer.schedule(new TimerWorker(timer),2000L,1000L);

 }

}

TimerWorker代码

import java.util.Timer;

import java.util.TimerTask;


public**classTimerWorker extends** TimerTask{

 Timertimer= null;


intindex = 0;

public TimerWorker(){}

publicTimerWorker(Timer timer){

this.timer = timer;

 }


 //编写重复定时任务

 @Override

public**void** run() {

if(index < 5){

    System.out.println("执行次数:"+index);

try {

     Thread.sleep(2000L);//执行时间休眠2s

    }catch(InterruptedException e) {

     e.printStackTrace();

    }

    System.out.println("task begin:"+this.scheduledExecutionTime());

    index++;

  }else{

    System.out.println("取消"+index);

    timer.cancel();

  }  

 }

}


timer.schedule(new TimerWorker(timer),2000L,1000L);

运行结果:

执行次数:0

task begin:1472635789100

执行次数:1

task begin:1472635791101 = 1472635789100 + 2000

执行次数:2

task begin:1472635793101

执行次数:3

task begin:1472635795102

执行次数:4

task begin:1472635797102

取消5

结论:间隔时间都是2s,下一次的执行时间点**=上一次程序执行完成的时间点+间隔时间** 1s


timer.scheduleAtFixedRate(new TimerWorker(timer),2000L,1000L);

运行结果:

执行次数:0

task begin:1472636554862

执行次数:1

task begin:1472636555862 = 1472636555862 + 1000

执行次数:2

task begin:1472636556862

执行次数:3

task begin:1472636557862

执行次数:4

task begin:1472636558862

取消5

结论:间隔时间都是1s,下一次的执行时间点**=上一次程序开始执行的时间点+间隔时间** 1s,并且前一个任务要执行2秒,而当前任务已经开始执行,因此两个任务间存在重叠,TimerWorker中需要考虑线程同步


1.4测试完整代码

TimerWorker代码如下:

import java.util.Timer;

import java.util.TimerTask;

import com.util.DateUtil;

public**classTimerWorker extends** TimerTask{

 Timertimer= null;


intindex = 0;

public TimerWorker(){


 }

publicTimerWorker(Timer timer){

this.timer = timer;

 }


 //编写重复定时任务

 @Override

public**void** run() {

if(index < 5){

    System.out.println("执行次数:"+index);

    System.out.println(DateUtil.getCurrentTimeStr());

    index++;

  }else{

    System.out.println("取消"+index);

    timer.cancel();

  }  

 }

}


TimerMain完整代码如下


import java.util.Calendar;

import java.util.Date;

import java.util.Timer;

importjava.util.TimerTask;

import com.util.DateUtil;

/**

*@author pjliang

*/

public**class**TimerMain {


static Timer timer = null;


public**staticvoid** main(String[] args) {

timer = new Timer();

  TimerWorkertask = newTimerWorker(timer);

  System.out.println(DateUtil.getCurrentTimeStr());

  //1.延迟5s=5000ms后调度任务task

timer.schedule(task, 5000L);


  //2.任务task将会在当天的15:27:00时被调度一次

  Calendar calendar = Calendar.getInstance();

  calendar.set(Calendar.HOUR_OF_DAY, 15);

  calendar.set(Calendar.MINUTE, 54);

  calendar.set(Calendar.SECOND, 0);

  Datetime = calendar.getTime();

timer.schedule(task, time);  

   //3.任务task延迟等待2s后开始调度,每次调度前最少等待1s

timer.schedule(task, 2000L, 1000L);


  //4.任务task在16:13:00开始调度,每次调度前最少等待1s

  Calendarcalendar = Calendar.getInstance();

  calendar.set(Calendar.HOUR_OF_DAY, 16);

  calendar.set(Calendar.MINUTE, 15);

  calendar.set(Calendar.SECOND, 0);

  Datetime = calendar.getTime();

timer.schedule(task, time,1000L);


  //5.任务task在16:15:00开始调度,每次调度频度是1s

  Calendarcalendar = Calendar.getInstance();

  calendar.set(Calendar.HOUR_OF_DAY, 16);

  calendar.set(Calendar.MINUTE, 15);

  calendar.set(Calendar.SECOND, 0);

  Datetime = calendar.getTime();

timer.scheduleAtFixedRate(task, time,1000L);


  //6.任务task在在延迟等待1s后开始调度,每次调度频度是1s

timer.scheduleAtFixedRate(task, 1000L,1L);

 }

}


1.5源码分析

构造方法1:无参构造方法,简单通过Timer为前缀构造一个线程名称:

public Timer() {

this("Timer-" + serialNumber());

}


构造方法2:传入了是否为守护线程,守护线程当且仅当主进程结束时,自动注销掉,而无需使用cancel来完成对timer的结束。

public Timer(boolean isDaemon) {

this("Timer-" + serialNumber(), isDaemon);

}


构造方法3:传递参数name来创建一个自定义名称的timer

public Timer(String name) {

this(name, true);

}


构造方法4:同时传递参数name和isDaemon来创建timer

public Timer(String name, boolean isDaemon) {

   thread.setName(name);

   thread.setDaemon(isDaemon);

   thread.start();

}


方法**schedule和方法scheduleAtFixedRate的几个重载源码**

1). public void schedule(TimerTask task, long delay)

public**voidschedule(TimerTask task, long** delay) {

if(delay < 0)

throw**new** IllegalArgumentException("Negativedelay.");

 sched(task, System.currentTimeMillis()+delay, 0);

}  

调用方法sched,

第一个参数task将任务传入;

第二个参数System.currentTimeMillis()是当前时间+延迟时间(如果是Date,参数2就是date.getTime());

第三个参数传入0,该参数代表时间片



2). publicvoid schedule(TimerTask task, long delay, longperiod)

public**voidschedule(TimerTask task, long** delay, longperiod) {

if(delay < 0)

throw**new** IllegalArgumentException("Negativedelay.");

if(period <= 0)

throw**new** IllegalArgumentException("Non-positiveperiod.");

 sched(task, System.currentTimeMillis()+delay, -period);

}

调用方法sched,

第一个参数task将任务传入;

第二个参数System.currentTimeMillis()是当前时间+延迟时间(如果是Date,参数2就是date.getTime());

第三个参数传入-period,该参数代表时间片,取反


3). publicvoid scheduleAtFixedRate(TimerTask task, longdelay, long period)

public**voidscheduleAtFixedRate(TimerTask task, long** delay, long period) {

if(delay < 0)

throw**new** IllegalArgumentException("Negativedelay.");

if(period <= 0)

throw**new** IllegalArgumentException("Non-positiveperiod.");

 sched(task, System.currentTimeMillis()+delay, period);

}

调用方法sched,

第一个参数task将任务传入;

第二个参数System.currentTimeMillis()是当前时间+延迟时间(如果是Date,参数2就是date.getTime());

第三个参数传入 period,该参数代表时间片,取正


4). privatevoid sched(TimerTask task, long time, longperiod)

private**voidsched(TimerTask task, long** time, longperiod) {

if(time < 0)

throw**new** IllegalArgumentException("Illegalexecution time.");

synchronized(queue){

if (!thread.newTasksMayBeScheduled)

throw**new** IllegalStateException("Timer alreadycancelled.");

synchronized(task.lock) {

if (task.state != TimerTask.VIRGIN)

throw**new** IllegalStateException(

         "Task already scheduled or cancelled");

     task.nextExecutionTime = time;

     task.period = period;

     task.state = TimerTask.SCHEDULED;

   }

   queue.add(task);

if (queue.getMin() == task)

     queue.notify();

 }

}

queue是一个队列,执行操作的是使用synchronized进行线程同步,所以是线程安全的,随后为task相关参数赋值,有nextExecutionTime(下一次执行时间),period(时间片),state(状态),最后将task放入queue队列中,执行一次notify操作

相关文章
|
8月前
|
监控 Linux 编译器
Linux C++ 定时器任务接口深度解析: 从理论到实践
Linux C++ 定时器任务接口深度解析: 从理论到实践
266 2
|
缓存 前端开发 JavaScript
vue3.0 watch 和 computed源码解析(举例图解)
彻底弄清楚 watch 和 computed 原理
|
机器学习/深度学习 PyTorch 算法框架/工具
PyTorch并行与分布式(三)DataParallel原理、源码解析、举例实战
PyTorch并行与分布式(三)DataParallel原理、源码解析、举例实战
875 0
【蓝桥杯嵌入式】STM32定时器的配置,解析预分频系数和重装载值与时钟频率的关系
【蓝桥杯嵌入式】STM32定时器的配置,解析预分频系数和重装载值与时钟频率的关系
1298 0
【嵌入式】窗户看门狗定时器概念详解+例题解析
题目 嵌入式系统使用WWDG窗口看门狗模块监视用户程序运行,假设看门狗的喂狗时间为20ms,PCLK1频率为36MHz,WDGTB[1:0]=10b。请计算看门狗的定时计数值(给出计算过程),并写出看门狗的初始化函数(注:使用寄存器方式程序)
457 0
蓝桥杯之单片机学习(九)——定时器的进阶综合案例解析
蓝桥杯之单片机学习(九)——定时器的进阶综合案例解析
251 0
|
存储 安全 Java
JDK集合源码之ArrayList解析(附带面试题举例)
JDK集合源码之ArrayList解析(附带面试题举例)
JDK集合源码之ArrayList解析(附带面试题举例)
|
2月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
86 2
|
9天前
|
存储 设计模式 算法
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。行为型模式分为类行为模式和对象行为模式,前者采用继承机制来在类间分派行为,后者采用组合或聚合在对象间分配行为。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象行为模式比类行为模式具有更大的灵活性。 行为型模式分为: • 模板方法模式 • 策略模式 • 命令模式 • 职责链模式 • 状态模式 • 观察者模式 • 中介者模式 • 迭代器模式 • 访问者模式 • 备忘录模式 • 解释器模式
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析

推荐镜像

更多