Java中的java.util.Timer是一个工具类,可以用于调度一个线程在将来的某一个时刻执行特定的任务。Java Timer类可以将一个任务定时执行一次,或者是以后以每隔一定的时间间隔来触发一次。

Java TimerTask

java.util.TimerTask是一个抽象类,也同时实现了Runnable接口的。我们可以继承这个类来创建我们自己的TimerTask之后由Timer来调度。

Java Timer举例

Java Timer类是线程安全的,多个线程可以共享一个Timer对象而不需要额外的同步操作。Timer类会使用java.util.TaskQueue来将Task以一定的时间间隔加入到队列之中,而且,在任何时候仅仅能有一个线程在运行TimerTask。举例来说,开发者创建了一个Timer每隔10秒来执行一次,但是单线程的执行需要使用20秒,那么Timer对象会持续将任务添加到队列中,只要线程的执行完成了,它会通知队列中另一个线程来立刻执行。

Java Timer类通过对象的waitnotify方法来调度任务。

参见如下代码:

package com.sapphire.threads;

import java.util.Date;
import java.util.Timer;
import java.util.TimerTask; public class MyTimerTask extends TimerTask { @Override
public void run() {
System.out.println("Timer task started at:"+new Date());
completeTask();
System.out.println("Timer task finished at:"+new Date());
} private void completeTask() {
try {
//assuming it takes 20 secs to complete the task
Thread.sleep(20000);
} catch (InterruptedException e) {
e.printStackTrace();
}
} public static void main(String args[]){
TimerTask timerTask = new MyTimerTask();
//running timer task as daemon thread
Timer timer = new Timer(true);
timer.scheduleAtFixedRate(timerTask, 0, 10*1000);
System.out.println("TimerTask started");
//cancel after sometime
try {
Thread.sleep(120000);
} catch (InterruptedException e) {
e.printStackTrace();
}
timer.cancel();
System.out.println("TimerTask cancelled");
try {
Thread.sleep(30000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

需要注意的是,上面的一个线程的执行会花掉20秒,但是Java的Timer对象调度的执行间隔是10秒执行一次,所以输出如下:

TimerTask started
Timer task started at:Fri Oct 14 12:59:27 CST 2016
Timer task finished at:Fri Oct 14 12:59:47 CST 2016
Timer task started at:Fri Oct 14 12:59:47 CST 2016
Timer task finished at:Fri Oct 14 13:00:07 CST 2016
Timer task started at:Fri Oct 14 13:00:07 CST 2016
Timer task finished at:Fri Oct 14 13:00:27 CST 2016
Timer task started at:Fri Oct 14 13:00:27 CST 2016
Timer task finished at:Fri Oct 14 13:00:47 CST 2016
Timer task started at:Fri Oct 14 13:00:47 CST 2016
Timer task finished at:Fri Oct 14 13:01:07 CST 2016
Timer task started at:Fri Oct 14 13:01:07 CST 2016
TimerTask cancelled
Timer task finished at:Fri Oct 14 13:01:27 CST 2016

输出也确认了一点,就是如果一个任务已经开始执行了,那么Timer会等待它的完成,而一旦完成,Timer会立刻开始执行队列中的下一个任务。

Java的对象可以以守护线程的方式来调度相关的任务。Timer的cancel()方法是用来结束Timer并抛弃其他的调度任务的。然而,这个方法不会影响现在正在执行的任务,而是让其继续运行下去。如果我们将Timer的运行配置为守护线程,那么无论我们是否调用cancel()方法,一旦用户线程完成执行,Timer都会立刻结束掉。

Timer类中包含多个schedule()方法,可以调度任务在指定时间执行一次,或者在一些延迟后来执行。Timer类中也包含了一些scheduleAtFixedRate()方法来以指定的时间间隔来运行一些任务。

注意:当使用Timer来进行任务调度的时候,开发者需要确认无时间间隔一定要大于线程的执行时间。否则,任务的队列会变得越来越长而实际的任务也会总是在执行。

前面的描述也相当于隐含着提到了Timer的可能的错误行为,那就是Timer执行任务的方式。Timer的实现是内部包含一个队列,和一个线程,然后来定时将任务添加到执行队列之中的。

public class Timer {
private final TaskQueue queue = new TaskQueue();
private final TimerThread thread = new TimerThread(queue);
}

这样就可能出现问题,如果将2个TimerTask加入到Timer中进行执行,如果其中一个Timer执行的比较忙,而另一个需要执行的又比较快,可能就会出现问题。举例来说,两个任务,一个每隔300秒执行一次,一个每隔5秒执行一次,如果第一个任务执行了20秒才结束,那么因为上面实现的原因,会将第二个任务阻塞20秒,而一口气执行四次。所以开发者在使用Timer来进行任务调度的时候,需要考虑性能以及可能出现的错误行为。

Java线程和多线程(十)——TimerTask的更多相关文章

  1. Java线程和多线程(十二)——线程池基础

    Java 线程池管理多个工作线程,其中包含了一个队列,包含着所有等待被执行的任务.开发者可以通过使用ThreadPoolExecutor来在Java中创建线程池. 线程池是Java中多线程的一个重要概 ...

  2. Java线程与多线程教程

    本文由 ImportNew - liken 翻译自 Journaldev.   Java线程是执行某些任务的轻量级进程.Java通过Thread类提供多线程支持,应用可以创建并发执行的多个线程. 应用 ...

  3. Java线程和多线程(十三)——Callable,Future,FutureTask

    在Java多线程之中,Callable和Future的使用时非常广泛的.在之前的文章中,我们了解了关于Java线程池基础的一些内容,知道如何提交Runnable的任务.但是,Runnable的任务是无 ...

  4. Java线程和多线程(三)——线程安全和同步

    线程安全在Java中是一个很重要的课题.Java提供的多线程环境支持使用Java线程.我们都知道多线程共享一些对象实例的话,可能会在读取和更新共享数据的事后产生数据不一致问题. 线程安全 之所以会产生 ...

  5. Java线程和多线程(一)——线程的基本概念

    Java 线程是一个轻量级执行任务的处理单元.Java提供了Thread类来支持多线程,开发者在应用中可以创建多个线程来支持并发执行任务. 在应用中存在两种类型的线程,用户线程和守护线程.当我们启动应 ...

  6. Java 线程与多线程

    Java是一门支持多线程的编程语言! 什么是进程? 计算机中内存.处理器.IO等资源操作都要为进程进行服务. 一个进程上可以创建多个线程,线程比进程更快的处理单元,而且所占用的资源也小,多线程的应用也 ...

  7. Java线程和多线程(八)——Thread Dump

    Java的Thread Dump就是列出JVM中所有激活状态的线程. Java Thread Dump Java Thread Dump在分析应用性能瓶颈和死锁的时候,是非常有效的. 下面将介绍多种不 ...

  8. Java线程和多线程(十五)——线程的活性

    当开发者在应用中使用了并发来提升性能的同时,开发者也需要注意线程之间有可能会相互阻塞.当整个应用执行的速度比预期要慢的时候,也就是应用没有按照预期的执行时间执行完毕.在本章中,我们来需要仔细分析可能会 ...

  9. Java线程和多线程(十四)——Synchronized关键字解析

    曾经有一个比较有趣的面试问题,那就是,关于使用synchronized关键字,是用在方法上面尾号,还是用在一个代码块上面为好? 答案就是使用锁定代码块为更好.因为这样不会锁定对象.当synchroni ...

随机推荐

  1. Perl Unicode全攻略

    Perl Unicode全攻略 耐心看完本文,相信你今后在unicode处理上不会再有什么问题. 本文内容适用于perl 5.8及其以上版本. perl internal form 在Perl看来, ...

  2. React中最基础的jsx语法

    import React, { Component } from 'react'; class App extends Component { render() { return ( <div ...

  3. (第六场)Singing Contest 【模拟】

    题目链接:https://www.nowcoder.com/acm/contest/144/A 标题:A.Singing Contest | 时间限制:1 秒 | 内存限制:256M Jigglypu ...

  4. caffe卷积层实现

    下图是jiayangqing在知乎上的回答,其实过程就是把image转换成矩阵,然后进行矩阵运算 卷积的实现在conv_layer层,conv_layer层继承了base_conv_layer层,ba ...

  5. HDU 1222 Wolf and Rabbit(数学,找规律)

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission( ...

  6. 创建VS工程使用神经网络库——FANN

    编译: sourceforge上的FANN库带VS2010的工程,我机器上装的VS2005,用不了,愁人,只能手动创建工程了,编译不过,度娘不管用,FQ麻烦,用雅虎搜到一个工程的创建配置,调整配置试一 ...

  7. tomcat解决端口号占用问题

    1.第一种方法 更改tomcat自己的端口号: conf 目录下 找到 server.xml,把默认的8080端口改个别的试试,tomcat 一般端口号改的要大于 6000,. 2.第二种方法 关闭端 ...

  8. js函数只触发一次

    如何让js中的函数只被执行一次?我们有时候会有这种需求,即让一个函数只执行一次,第二次调用不会返回任何有价值的值,也不会报错.下面将通过三个小demo展示使用的方法,当做个人笔记. 1.通过闭包来实现 ...

  9. LeetCode 翻转链表

    基本思路 从元首节点之后每次取一个节点,并将节点接到元首节点前面 代码实现 /** * Definition for singly-linked list. * struct ListNode { * ...

  10. Spring、Spring Boot、Spring Frame、Spring MVC的区别

    Spring框架就像一个厂商,其下有很多产品,如Spring Boot.Spring Frame.Spring Cloud等等. Spring Boot用于快速.方便.简单的搭建一个Spring项目. ...