Timer类主要负责计划任务,也就是在指定的时间开始执行某一个任务。

方法schedule(TimerTask task, Date time)
public class Task {
private static Timer timer = new Timer();
static public class MyTask extends TimerTask{
@Override
public void run() {
System.out.println("Task运行了,时间为:" + new Date());
}
}
public static void main(String[] args) {
try {
MyTask myTask = new MyTask();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateString = "2016-07-09 21:30:19";
Date date = sdf.parse(dateString);
System.out.println("main启动时间为:" + new Date());
timer.schedule(myTask, date);
} catch (Exception e) {
e.printStackTrace();
}
}
}

程序运行结果如下:

main启动时间为:Sat Jul 09 21:28:54 CST 2016
Task运行了,时间为:Sat Jul 09 21:30:19 CST 2016

任务虽然执行完了,但是进程还没有销毁。

创建Timer的源码如下:

public Timer() {
this("Timer-" + serialNumber());
} public Timer(String name) {
thread.setName(name);
thread.start();
}

由构造方法可知,创建一个Timer就是启动一个新的线程,这个新启动的线程并不是守护线程,它就一直在运行。

将新创建的timer改成守护线程如下:

public class Task {
private static Timer timer = new Timer(true);
static public class MyTask extends TimerTask{
@Override
public void run() {
System.out.println("Task运行了,时间为:" + new Date());
}
}
public static void main(String[] args) {
try {
MyTask myTask = new MyTask();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateString = "2016-07-09 21:42:19";
Date date = sdf.parse(dateString);
System.out.println("main启动时间为:" + new Date());
timer.schedule(myTask, date);
} catch (Exception e) {
e.printStackTrace();
}
}
}

此时控制台打印结果如下:

main启动时间为:Sat Jul 09 21:41:59 CST 2016

由于新创建的Timer线程是守护线程,main线程运行完成之后迅速结束当前进程的运行。TimerTask中的任务不会得到执行。


若执行任务的时间早于当前时间,则会立即执行任务。

public class Task {
private static Timer timer = new Timer();
static public class MyTask extends TimerTask{
@Override
public void run() {
System.out.println("Task运行了,时间为:" + new Date());
}
}
public static void main(String[] args) {
try {
MyTask myTask = new MyTask();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateString = "2016-07-09 21:42:19";
Date date = sdf.parse(dateString);
System.out.println("main启动时间为:" + new Date());
timer.schedule(myTask, date);
} catch (Exception e) {
e.printStackTrace();
}
}
}

程序运行结果如下:

main启动时间为:Sat Jul 09 21:47:29 CST 2016
Task运行了,时间为:Sat Jul 09 21:47:29 CST 2016

多个TimerTask任务及延时的测试

Timer中允许有多个TimerTask任务

public class Task {
private static Timer timer = new Timer();
static public class MyTask1 extends TimerTask{
@Override
public void run() {
System.out.println("Task1运行了,时间为:" + new Date());
}
}
static public class MyTask2 extends TimerTask{
@Override
public void run() {
System.out.println("Task2运行了,时间为:" + new Date());
}
}
public static void main(String[] args) {
try {
MyTask1 myTask1 = new MyTask1();
MyTask2 myTask2 = new MyTask2();
SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateString1 = "2016-07-09 22:04:19";
String dateString2 = "2016-07-09 22:05:19";
Date date1 = sdf1.parse(dateString1);
Date date2 = sdf2.parse(dateString2);
System.out.println("main启动时间为:" + new Date());
timer.schedule(myTask1, date1);
timer.schedule(myTask2, date2);
} catch (Exception e) {
e.printStackTrace();
}
}
}

程序运行结果如下:

main启动时间为:Sat Jul 09 22:04:09 CST 2016
Task1运行了,时间为:Sat Jul 09 22:04:19 CST 2016
Task2运行了,时间为:Sat Jul 09 22:05:19 CST 2016

TimerTask是以队列的方式一个一个被顺序执行的,所以执行的时间有可能和预期的时间不一致。如果前面的任务耗时较长,后面的任务执行时间有可能被推迟。

public class Task {
private static Timer timer = new Timer();
static public class MyTask1 extends TimerTask{
@Override
public void run() {
System.out.println("Task1运行了,时间为:" + new Date());
try {
Thread.sleep(20000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
static public class MyTask2 extends TimerTask{
@Override
public void run() {
System.out.println("Task2运行了,时间为:" + new Date());
}
}
public static void main(String[] args) {
try {
MyTask1 myTask1 = new MyTask1();
MyTask2 myTask2 = new MyTask2();
SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateString1 = "2016-07-09 22:08:19";
String dateString2 = "2016-07-09 22:08:29";
Date date1 = sdf1.parse(dateString1);
Date date2 = sdf2.parse(dateString2);
System.out.println("main启动时间为:" + new Date());
timer.schedule(myTask1, date1);
timer.schedule(myTask2, date2);
} catch (Exception e) {
e.printStackTrace();
}
}
}

程序运行结果如下:

main启动时间为:Sat Jul 09 22:08:06 CST 2016
Task1运行了,时间为:Sat Jul 09 22:08:19 CST 2016
Task2运行了,时间为:Sat Jul 09 22:08:39 CST 2016

方法schedule(TimerTask task, Date firstTime, long period)

该方法的作用是在指定的日期之后,按指定的时间间隔周期性地无限循环地执行某一个任务

public class Main {
static public class MyTask extends TimerTask{
@Override
public void run() {
System.out.println("开始运行,时间:" + new Date());
}
public static void main(String[] args) {
try {
MyTask task = new MyTask();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Timer timer = new Timer();
String dateString = "2016-07-09 22:17:55";
Date date = sdf.parse(dateString);
System.out.println("main开始执行时间:" + new Date());
timer.schedule(task, date, 4000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}

程序执行结果如下:

main开始执行时间:Sat Jul 09 22:17:30 CST 2016
开始运行,时间:Sat Jul 09 22:17:55 CST 2016
开始运行,时间:Sat Jul 09 22:17:59 CST 2016
开始运行,时间:Sat Jul 09 22:18:03 CST 2016
开始运行,时间:Sat Jul 09 22:18:07 CST 2016
......

TimerTask类的cancel()方法

TimerTask类的cancel()方法的作用是将自身从任务队列中清除

public class Task {
private static Timer timer = new Timer();
static public class MyTask1 extends TimerTask{
@Override
public void run() {
System.out.println("Task1运行了,时间为:" + new Date());
this.cancel();
}
}
static public class MyTask2 extends TimerTask{
@Override
public void run() {
System.out.println("Task2运行了,时间为:" + new Date());
}
}
public static void main(String[] args) {
try {
MyTask1 myTask1 = new MyTask1();
MyTask2 myTask2 = new MyTask2();
SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateString1 = "2016-07-09 22:08:19";
String dateString2 = "2016-07-09 22:08:29";
Date date1 = sdf1.parse(dateString1);
Date date2 = sdf2.parse(dateString2);
System.out.println("main启动时间为:" + new Date());
timer.schedule(myTask1, date1, 4000);
timer.schedule(myTask2, date2, 4000);
} catch (Exception e) {
e.printStackTrace();
}
}
}

程序运行结果如下:

main启动时间为:Sat Jul 09 22:24:15 CST 2016
Task1运行了,时间为:Sat Jul 09 22:24:15 CST 2016
Task2运行了,时间为:Sat Jul 09 22:24:15 CST 2016
Task2运行了,时间为:Sat Jul 09 22:24:19 CST 2016
Task2运行了,时间为:Sat Jul 09 22:24:23 CST 2016
......

Timer类的cancel()方法

Timer类的cancel()方法的作用是将任务队列中的全部任务清除

public class Task {
private static Timer timer = new Timer();
static public class MyTask1 extends TimerTask{
@Override
public void run() {
System.out.println("Task1运行了,时间为:" + new Date());
timer.cancel();
}
}
static public class MyTask2 extends TimerTask{
@Override
public void run() {
System.out.println("Task2运行了,时间为:" + new Date());
}
}
public static void main(String[] args) {
try {
MyTask1 myTask1 = new MyTask1();
MyTask2 myTask2 = new MyTask2();
SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateString1 = "2016-07-09 22:08:19";
String dateString2 = "2016-07-09 22:08:29";
Date date1 = sdf1.parse(dateString1);
Date date2 = sdf2.parse(dateString2);
System.out.println("main启动时间为:" + new Date());
timer.schedule(myTask1, date1, 4000);
timer.schedule(myTask2, date2, 4000);
} catch (Exception e) {
e.printStackTrace();
}
}
}

程序运行结果如下:

main启动时间为:Sat Jul 09 22:26:21 CST 2016
Task1运行了,时间为:Sat Jul 09 22:26:21 CST 2016

全部任务都被清除,并且进程被销毁。


Timer类的cancel()方法注意事项
public class Main {
static int i = 0;
static public class MyTask extends TimerTask{ @Override
public void run() {
System.out.println("正常执行:" + i);
}
}
public static void main(String[] args) throws ParseException {
while (true) {
i++;
Timer timer = new Timer();
MyTask task = new MyTask();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateString = "2016-07-09 22:32:55";
Date date = sdf.parse(dateString);
timer.schedule(task, date);
timer.cancel();
}
}
}

程序运行结果如下:

......
正常执行:12466
正常执行:12486
正常执行:12592
正常执行:12656
正常执行:12773
正常执行:15554
正常执行:15968
......

这是因为Timer类中的cancel()没有争抢到queue锁,所以TimerTask类中的任务继续正常执行。


方法schedule(TimerTask task, long delay)的使用

方法schedule(TimerTask task, long delay)的作用是以当前时间为基准延迟delay毫秒数执行

public class Main {
static public class MyTask extends TimerTask{ @Override
public void run() {
System.out.println("执行时间:" + new Date());
}
}
public static void main(String[] args) throws ParseException {
Timer timer = new Timer();
MyTask task = new MyTask();
System.out.println("当前时间:" + new Date());
timer.schedule(task, 5000);
}
}

程序运行结果如下:

当前时间:Sat Jul 09 22:37:45 CST 2016
执行时间:Sat Jul 09 22:37:50 CST 2016

schedule(task, delay, period)的使用

schedule(task, delay, period)的作用是以当前时间为基准延迟delay毫秒数,以period毫秒数为间隔无限循环周期执行

public class Main {
static public class MyTask extends TimerTask{ @Override
public void run() {
System.out.println("执行时间:" + new Date());
}
}
public static void main(String[] args) throws ParseException {
Timer timer = new Timer();
MyTask task = new MyTask();
System.out.println("当前时间:" + new Date());
timer.schedule(task, 5000, 2000);
}
}

程序运行结果如下:

当前时间:Sat Jul 09 22:40:14 CST 2016
执行时间:Sat Jul 09 22:40:19 CST 2016
执行时间:Sat Jul 09 22:40:21 CST 2016
执行时间:Sat Jul 09 22:40:23 CST 2016
......

schedule方法任务不延时
public class Main {
private static Timer timer = new Timer();
private static int runCount = 0;
static public class MyTask extends TimerTask{ @Override
public void run() {
try {
System.out.println("begin run," + new Date());
Thread.sleep(1000);
System.out.println("end run," + new Date());
runCount++;
if (runCount == 5) {
timer.cancel();
}
} catch (Exception e) {
e.printStackTrace();
}
} }
public static void main(String[] args) {
try {
MyTask task = new MyTask();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateString = "2016-07-10 10:26:35";
Date date = sdf.parse(dateString);
System.out.println("main开始时间:" + new Date());
timer.schedule(task, date, 3000);
} catch (Exception e) {
e.printStackTrace();
}
}
}

程序运行结果如下:

main开始时间:Sun Jul 10 10:26:27 CST 2016
begin run,Sun Jul 10 10:26:35 CST 2016
end run,Sun Jul 10 10:26:36 CST 2016
begin run,Sun Jul 10 10:26:38 CST 2016
end run,Sun Jul 10 10:26:39 CST 2016
begin run,Sun Jul 10 10:26:41 CST 2016
end run,Sun Jul 10 10:26:42 CST 2016
begin run,Sun Jul 10 10:26:44 CST 2016
end run,Sun Jul 10 10:26:45 CST 2016
begin run,Sun Jul 10 10:26:47 CST 2016
end run,Sun Jul 10 10:26:48 CST 2016

在不延时的情况下,如果执行任务的时间没有被延时,则下一次执行任务的时间是上一次任务的开始时间加上delay时间。


schedule方法任务延时
public class Main {
private static Timer timer = new Timer();
private static int runCount = 0;
static public class MyTask extends TimerTask{ @Override
public void run() {
try {
System.out.println("begin run," + new Date());
Thread.sleep(5000);//任务耗时5秒
System.out.println("end run," + new Date());
runCount++;
if (runCount == 5) {
timer.cancel();
}
} catch (Exception e) {
e.printStackTrace();
}
} }
public static void main(String[] args) {
try {
MyTask task = new MyTask();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateString = "2016-07-10 17:00:00";
Date date = sdf.parse(dateString);
System.out.println("main开始时间:" + new Date());
timer.schedule(task, date, 3000);//周期为3秒
} catch (Exception e) {
e.printStackTrace();
}
}
}

程序运行结果如下:

main开始时间:Sun Jul 10 16:59:31 CST 2016
begin run,Sun Jul 10 17:00:00 CST 2016
end run,Sun Jul 10 17:00:05 CST 2016
begin run,Sun Jul 10 17:00:05 CST 2016
end run,Sun Jul 10 17:00:10 CST 2016
begin run,Sun Jul 10 17:00:10 CST 2016
end run,Sun Jul 10 17:00:15 CST 2016
begin run,Sun Jul 10 17:00:15 CST 2016
end run,Sun Jul 10 17:00:20 CST 2016
begin run,Sun Jul 10 17:00:20 CST 2016
end run,Sun Jul 10 17:00:25 CST 2016

任务执行周期为3秒,任务每次执行耗时5秒。从运行结果看,如果执行任务的时间被延时,那么下一次任务的执行时间以上一次任务“结束”时的时间为参考来计算。


scheduleAtFixedRate方法任务不延时
public class Main {
private static Timer timer = new Timer();
private static int runCount = 0;
static public class MyTask extends TimerTask{ @Override
public void run() {
try {
System.out.println("begin run," + new Date());
Thread.sleep(2000);//任务耗时2秒
System.out.println("end run," + new Date());
runCount++;
if (runCount == 5) {
timer.cancel();
}
} catch (Exception e) {
e.printStackTrace();
}
} }
public static void main(String[] args) {
try {
MyTask task = new MyTask();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateString = "2016-07-10 17:18:00";
Date date = sdf.parse(dateString);
System.out.println("main开始时间:" + new Date());
timer.scheduleAtFixedRate(task, date, 3000);//周期为3秒
} catch (Exception e) {
e.printStackTrace();
}
}
}

程序运行结果如下:

main开始时间:Sun Jul 10 17:17:51 CST 2016
begin run,Sun Jul 10 17:18:00 CST 2016
end run,Sun Jul 10 17:18:02 CST 2016
begin run,Sun Jul 10 17:18:03 CST 2016
end run,Sun Jul 10 17:18:05 CST 2016
begin run,Sun Jul 10 17:18:06 CST 2016
end run,Sun Jul 10 17:18:08 CST 2016
begin run,Sun Jul 10 17:18:09 CST 2016
end run,Sun Jul 10 17:18:11 CST 2016
begin run,Sun Jul 10 17:18:12 CST 2016
end run,Sun Jul 10 17:18:14 CST 2016

schedule和scheduleAtFixedRate的区别在于,如果指定开始执行的时间在当前系统运行时间之前,scheduleAtFixedRate会把已经过去的时间也作为周期执行,而schedule不会把过去的时间算上。


scheduleAtFixedRate方法任务延时
public class Main5 {
private static Timer timer = new Timer();
private static int runCount = 0;
static public class MyTask extends TimerTask{ @Override
public void run() {
try {
System.out.println("begin run," + new Date());
Thread.sleep(5000);//任务耗时5秒
System.out.println("end run," + new Date());
runCount++;
if (runCount == 5) {
timer.cancel();
}
} catch (Exception e) {
e.printStackTrace();
}
} }
public static void main(String[] args) {
try {
MyTask task = new MyTask();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateString = "2016-07-10 17:21:40";
Date date = sdf.parse(dateString);
System.out.println("main开始时间:" + new Date());
timer.scheduleAtFixedRate(task, date, 3000);//周期为3秒
} catch (Exception e) {
e.printStackTrace();
}
}
}

程序运行结果如下:

main开始时间:Sun Jul 10 17:21:35 CST 2016
begin run,Sun Jul 10 17:21:40 CST 2016
end run,Sun Jul 10 17:21:45 CST 2016
begin run,Sun Jul 10 17:21:45 CST 2016
end run,Sun Jul 10 17:21:50 CST 2016
begin run,Sun Jul 10 17:21:50 CST 2016
end run,Sun Jul 10 17:21:55 CST 2016
begin run,Sun Jul 10 17:21:55 CST 2016
end run,Sun Jul 10 17:22:00 CST 2016
begin run,Sun Jul 10 17:22:00 CST 2016
end run,Sun Jul 10 17:22:05 CST 2016

任务开始时间间隔为5秒。

Java多线程编程核心技术--定时器的更多相关文章

  1. Java多线程编程核心技术

    Java多线程编程核心技术 这本书有利于对Java多线程API的理解,但不容易从中总结规律. JDK文档 1. Thread类 部分源码: public class Thread implements ...

  2. 《Java 多线程编程核心技术》- 笔记

    作为业务开发人员,能够在工作中用到的技术其实不多.虽然平时老是说什么,多线程,并发,注入,攻击!但是在实际工作中,这些东西不见得用得上.因为,我们用的框架已经把这些事做掉了. 比如web开发,外面有大 ...

  3. 《Java多线程编程核心技术》知识梳理

    <Java多线程编程核心技术> @author ergwang https://www.cnblogs.com/ergwang/ 文章末尾附pdf和png下载链接 第1章 Java多线程技 ...

  4. Java多线程编程核心技术---学习分享

    继承Thread类实现多线程 public class MyThread extends Thread { @Override public void run() { super.run(); Sys ...

  5. Java多线程编程核心技术---对象及变量的并发访问(二)

    数据类型String的常量池特性 在JVM中具有String常量池缓存的功能. public class Service { public static void print(String str){ ...

  6. 《Java多线程编程核心技术》推荐

    写这篇博客主要是给猿友们推荐一本书<Java多线程编程核心技术>. 之所以要推荐它,主要因为这本书写得十分通俗易懂,以实例贯穿整本书,使得原本抽象的概念,理解起来不再抽象. 只要你有一点点 ...

  7. 《java多线程编程核心技术》(一)使用多线程

    了解多线程 进程和多线程的概念和线程的优点: 提及多线程技术,不得不提及"进程"这个概念.百度百科对"进程"的解释如下: 进程(Process)是计算机中的程序 ...

  8. Thread.currentThread()和this的区别——《Java多线程编程核心技术》

    前言:在阅读<Java多线程编程核心技术>过程中,对书中程序代码Thread.currentThread()与this的区别有点混淆,这里记录下来,加深印象与理解. 具体代码如下: pub ...

  9. Java多线程编程核心技术(三)多线程通信

    线程是操作系统中独立的个体,但这些个体如果不经过特殊的处理就不能成为一个整体.线程间的通信就是成为整体的必用方案之一,可以说,使线程间进行通信后,系统之间的交互性会更强大,在大大提高CPU利用率的同时 ...

随机推荐

  1. 轻快的VIM(三):删除

    这一节我们来看看删除,删除命令比较简单,不过要使删除更有效率 你需要配合我们第一节中讲的各种移动命令 字符删除 x 删除光标所在处字符 X 删除光标所在前字符 这里没有什么可注意的地方,但需要说明一下 ...

  2. 【HDU 5832】A water problem(大数取模)

    1千万长度的数对73和137取模.(两个数有点像,不要写错了) 效率要高的话,每15位取一次模,因为取模后可能有3位,因此用ll就最多15位取一次. 一位一位取模也可以,但是比较慢,取模运算是个耗时的 ...

  3. GCD详解

    什么是GCD? Grand Central Dispatch或者GCD,是一套低层API,提供了一种新的方法来进行并发程序编写.从基本功能上讲,GCD有点像 NSOperationQueue,他们都允 ...

  4. 让人又爱又恨的char(字符型)

    今天来总结一下char型,平常写算法的时候对这个东西感觉都有一点绕着走,说到底还是对这部分的知识不熟悉所以有点怕他,不过以后不要怕,今天来总结一下 首先,说到字符型数据类型,char型,恩它是一种数据 ...

  5. bzoj1724: [Usaco2006 Nov]Fence Repair 切割木板

    #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> ...

  6. Jenkins的FTP上传插件Publish Over FTP Plugin设置支持中文路径

    [系统管理]->[系统设置]->[Publish over FTP]->[Control encoding]->输入[GB2312]或者[UTF-8]

  7. Allegro使用技巧

    1.可以把outline及螺丝孔位置做成单独的mechanical symbol.因为板子外形和螺丝孔位置,多是从机构工程师手里拿来的DXF,新建mechanical symbol后,导入DXF到bo ...

  8. Android开发环境搭建中的一些小问题记录

    1.由于市场上大多数教程是基于Eclipse,而AndroidStudio显然是大势所趋,所有我在电脑上同时搭建了两个IDE,直接在官网下载AndroidStudio比较好,因为SDK,AVD都集成了 ...

  9. [U3D 画起重机,绑脚本和控制它运动的基本操作]

    之前在学习Unity3D,不知为何网上的教学资源真是少啊...我某段时间还卡在不知如何让物体绑个脚本自动运动.. 之所以要学习U3D是因为导师让我做的IOS项目里有个需要模拟起重机,从而控制真实起重机 ...

  10. spring jdbc分离数据库代码和java代码

    读取配置文件类 package com.eshore.ismp.contract.sql; import java.io.FileInputStream; import java.io.FileNot ...