设计一个timer类,属性包括小时,分,秒,然后编写此块含有代理对象main方法的类创建一个Timer对象进行测试

定时器:.NET Framework类库中的Timer类比较
在客户端程序和服务器组件(包括windows服务)中,timer(定时器)通常扮演着一个重要角色。编写高效的timer驱动的托管代码,需要对程序流程和.net线程模型的精妙有清晰的理解。.NET Framework 类库提供了三个不同的timer类:System.Windows.Forms.Timer, System,Timers.Timer 和 System.Threading.Timer。每个Timer类被设计优化用于不同的场合。本文研究了这三个Timer类,帮组你理解如何及何时该使用哪个类。
System.Windows.Forms.Timer
System.Timers.Timer
System.Threading.Timer
定时器的线程安全编程
处理timer事件的重入
Microsoft& Windows& 中的Timer对象在行为发生时允许你进行控制。Timer最常见的一些用法是有规律的定时启动一个进程,设置事件发生的间隔,在处理图像时维持一致的动画速度(不管处理器的速度如何)。在过去,对于使用Visual Basic&的开发人员来说, Timer甚至能用来模拟多任务。
如你所想,微软.NET Framework为你提供了处理这些任务所需的工具。在.NET Framework类库中有三个不同的Timer类:System.Windows.Forms.Timer, System,Timers.Timer 和 System.Threading.Timer。前两个类出现在Visual Studio& .NET 工具箱中,你可以直接把它们拖拽到Windows窗体设计器或组件设计器。如果你不小心,这时麻烦就开始了。
Visual Studio .NET 工具箱在Windows窗体页和组件页都有一个Timer控件(见图1)。很容易就用错了,或者更糟的是没有认识到它们是不同的。仅当目标是Windows窗体设计器时,使用Windows窗体页上的Timer控件。这个控件会在你的窗体上放置一个System.Windows.Forms.Timer类的实例。正如工具箱中的其它控件,你可以让Visual Studio .NET自动生成,或者也可以自己手工实例化、初始化这个类。
图1 定时器控件
组件页上的Timer控件可以安全地用于任何类。这个控件会创建System.Timers.Timer类的实例。如果你使用Visual Studio .NET 工具箱,无论是在Windows窗体设计器,还是在组件设计器,你都可以安全的使用这个Timer。当你处理一个继承自ponent的类(例如处理Windows服务)时,Visual Studio .NET会使用组件设计器。System.Threading.Timer类不在Visual Studio .NET 工具箱中。它稍微复杂些,但也提供了更高级的控制,稍后你将在本文看到。
我们首先研究一下System.Windows.Forms.Timer和System.Timers.Timer。这两个类有非常相似的对象模型。一会儿我会探究更高级的Sytem.Threading.Timer类。图2是我在这篇文章中引用的例子程序的屏幕截图。这个程序将帮助你更清晰的认识这几个类。你可以从文章上方的链接完整代码,并用它做试验。
图2 例子程序
System.Windows.Forms.Timer
如果你在找一个节拍器,你就找错地方了。这个Timer类触发的定时器事件与你的Windows窗体应用程序的其余代码是同步的。这就是说,正在执行的应用程序代码永远也不会被这个Timer类的实例抢占(假定你没有调用Application.DoEvents)。就像一个典型的Windows窗体应用程序的其余代码一样,这种Timer类的Timer事件处理器中的任何代码都是使用应用程序的UI线程来执行。在空闲时间,UI线程也负责处理应用程序的Windows消息队列中的所有消息,其中包括Windows API消息,也包括这种Timer类触发的Tick事件。当应用程序没有忙于做其他事时,UI线程就处理这些消息。
如果你在Visual Studio .NET之前,写过VB代码,你可能知道在基于Windows的应用程序中,允许UI线程在执行事件处理器时响应Windows消息的唯一方法,就是调用Application.DoEvents方法。正如VB中一样,在.NET Framework中调用Application.DoEvents会导致一些问题。Application.DoEvents移交控制给UI消息泵,允许对所有未处理的事件进行处理。这会改变我刚才提到的程序执行路径。如果在你代码里调用Application.DoEvents,你的程序流程会被中断,以便处理这个Timer类的实例所触发的定时器事件。这会导致不可预料的行为,使调试变得困难。
当我们执行例子程序,这个Timer类的行为就明显了。点击例子程序的Start按钮,然后点击Sleep按钮,最后点击Stop按钮,将会产生下面的输出:
System.Windows.Forms.Timer Started @ 4:09:28 PM
--& Timer Event 1 @ 4:09:29 PM on Thread: UIThread
--& Timer Event 2 @ 4:09:30 PM on Thread: UIThread
--& Timer Event 3 @ 4:09:31 PM on Thread: UIThread
Sleeping for 5000 ms...
--& Timer Event 4 @ 4:09:36 PM on Thread: UIThread
System.Windows.Forms.Timer Stopped @ 4:09:37 PM
例子程序把System.Windows.Forms.Timer类的Interval属性设置为1000毫秒。正如你看到的,如果在主UI线程休眠(5秒)时,timer事件处理器继续捕获timer事件,那么一旦UI线程再次被唤醒时,就应该显示5个timer事件&&UI线程休眠时每秒钟一个。然而,在UI线程休眠时,timer处于挂起状态。
用System.Windows.Forms.Timer已经够简单了&&它有一个非常简单直观的编程接口。Start和Stop方法提供了一个设置Enable属性(对Win32& SetTimer/ KillTimer 函数的轻量级封装)的替代方法。刚才提到的Interval属性,是不言自明的。尽管技术上,你可以把Interval属性设置得低到一毫秒,但你应该知道.NET Framework文档中说这个属性只能精确到大约55毫秒(假设UI线程可用于处理)。
捕获System.Windows.Forms.Timer类的实例触发的事件,是通过把Tick事件关联到标准的EventHandler代理来实现的,如下面例子中的代码片段所示:
System.Windows.Forms.Timer tmrWindowsFormsTimer = new
&&& System.Windows.Forms.Timer();
tmrWindowsFormsTimer.Interval = 1000;
tmrWindowsFormsTimer.Tick += new
&&& EventHandler(tmrWindowsFormsTimer_Tick);
tmrWindowsFormsTimer.Start();
private void tmrWindowsFormsTimer_Tick(object sender,
&&& System.EventArgs e) {
& //Do something on the UI thread...
System.Timers.Timer
.NET Framework文档之处System.Timers.Timer是一个基于服务器的定时器,是为多线程环境进行设计和优化的。这个Timer类的实例可以从多线程中安全的访问。不像System.Windows.Forms.Timer,System.Timers.Timer类默认会从公共语言运行时的线程池获取一个工作线程(worker thread)来调用你的timer事件处理器。这意味着你的Elapsed事件处理器中的代码必须遵守Win32编程的黄金规则:控件的实例绝不能被除实例化它的线程以外的任何其他线程访问。
System.Timers.Timer类提供了一个简单的方式处理这样的困境&&它暴露了一个公有的SynchronizingObject属性。把这个属性设置成Windows窗体的一个实例(或Windows窗体上的一个控件),可以保证你的Elapsed事件处理器中的代码运行在SynchronizingObject 被实例化的同一个线程。
如果你使用Visual Studio .NET工具箱,Visual Studio .NET会自动把SynchronizingObject属性设置为当前窗体。起初可能看起来,使用有SynchronizingObject属性的这个Timer类,使其在功能上与使用System.Windows.Forms.Timer等同。对于大部分功能,确实是这样。当操作通知System.Timers.Timer类启用的定时时间已过,定时器使用SynchronizingObject.BeginInvoke方法在创建SynchronizingObject的底层handle的线程上执行Elapsed事件代理。事件处理器会被阻塞,直到UI线程能处理它。然而,不像 System.Windows.Forms.Timer,事件最终还是会被触发。就像你在图2看到的,当UI线程不能处理时, System.Windows.Forms.Timer不会触发事件。而System.Timers.Timer会把事件排到队列中,等待UI线程可用时进行处理。
图3显示了如何使用SynchronizingObject 属性。你可以使用例子程序分析这个类,选择 System.Timers.Timer 单选按钮,按照执行System.Windows.Forms.Timer同样的顺序执行这个类。这样做会产生图4所示输出。
图3 使用SynchronizingObject属性
System.Timers.Timer tmrTimersTimer = new System.Timers.Timer();
tmrTimersTimer.Interval = 1000;
tmrTimersTimer.Elapsed += new
&&& ElapsedEventHandler(tmrTimersTimer_Elapsed);
tmrTimersTimer.SynchronizingObject = //Synchronize with
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& //the current form...
tmrTimersTimer.Start();
private void tmrTimersTimer_Elapsed(object sender,
&&& System.Timers.ElapsedEventArgs e) {
& // Do something on the UI thread (same thread the form was
& // created on)...
& // If we didnt set SynchronizingObject we would be on a
& // worker thread...
您对本文章有什么意见或着疑问吗?请到您的关注和建议是我们前行的参考和动力&&
您的浏览器不支持嵌入式框架,或者当前配置为不显示嵌入式框架。8971人阅读
System.Threading.Timer&是一个简单的轻量计时器,它使用回调方法并由线程池线程提供服务。在必须更新用户界面的情况下,建议不要使用该计时器,因为它的回调不在用户界面线程上发生。在此类情况下,System.Windows.Threading.DispatcherTimer&是更好的选择,因为其事件是在用户界面线程上引发的。&
多线程计时器
1:System.Threading.Timer
2:System.Timers.Timer
特殊目的的单线程计时器:
1:System.Windows.Forms.Timer(Windows Forms Timer)
2:System.Windows.Threading.DispatcherTimer(WPF timer);
多线程计时器比较强大,精确,而且可扩展性强;
单线程计时器比较安全,对于更新 Windows Forms controls或者WPF这种简单任务来说更方便。
System.Threading.Timer是最简单的多线程计时器。在下面的例子中,定时器在5秒后开始定时1秒的调用Tick方法。
publicstaticvoidMain()
//5秒后开始运行,接着每隔1秒的调用Tick方法
Timertmr=newTimer(Tick,&tick...&,);
Console.ReadLine();
tmr.Dispose();
staticvoidTick(objectdata)
Console.WriteLine(data);
.net framework提供的另一个计时器System.Timers.Timer.简单的对System.Threading.Timer进行了包装。增加了下面几个特性。
实现了Component,所以可以在设计器显示。代替Change方法的一个Interval属性代替callback委托的一个Elapsed事件启动和停止timer的Enabled属性,默认是false。为了避免Enabled造成混乱,提供了Start和Stop方法。是否在每次指定的间隔结束时引发Elapsed时间,还是仅间隔第一次结束后运行的AutoReset属性。在WPF或Windows Forms中安全的调用方法的SynchronizingObject对象。publicstaticvoidMainThread()
Timertmr=newTimer();
tmr.Interval=500;
tmr.Elapsed+=newElapsedEventHandler(tmr_Elapsed);
tmr.Start();
Console.ReadLine();
tmr.Stop();
Console.ReadLine();
tmr.Start();
Console.ReadLine();
tmr.Dispose();
staticvoidtmr_Elapsed(objectsender,ElapsedEventArgse)
Console.WriteLine(&Tick...&);
单线程计时器:
1:System.Windows.Forms.Timer(Windows Forms Timer)
2:System.Windows.Threading.DispatcherTimer(WPF timer);
单线程计时器是被设计成属于他们执行环境的计时器,如果你在一个Windows服务应用程序中使用Windows Forms的Timer,timer 事件并不会被触发,只有在对应的环境下才会被触发。
像System.Timers.Timer一样,他们也提供了相同的成员(Interval,Tick,Start,Stop),但是他们内部的工作原理不同,
WPF和Windows Forms的计时器使用消息循环机制来取代线程池产生消息的机制。
这意味着Tick事件总是在创建timer的那个线程上执行,同时也意味着如果上一个Tick消息还未被处理,即使时间超过了间隔时间,在消息循环中也只存在一个Tick消息。
下面是它们的优点:
你可以忘记线程安全。一个Tick事件在前一个Tick事件被处理完毕前不会被触发。你可以直接在Tick事件处理代码中更新控件,不需要调用Control.Invoke或Dispatcher.Invoke.
看下在Winform中使用单线程定时器的效果:
//基于Windows消息循环的单线程计时器
privateSystem.Windows.Forms.Timertimer=newTimer(){};
publicForm1()
InitializeComponent();
timer.Tick+=newEventHandler(timer_Tick);
timer.Enabled=
voidtimer_Tick(objectsender,EventArgse)
//模拟的做一些耗时的操作
System.Threading.Thread.Sleep(2000);
如果运行上面的代码,会发现UI界面响应速度很慢,
原理上面已经介绍了:单线程计时器基于Windows消息循环,应用程序会同步的处理计时器的消息。
解决这个问题的方法是使用多线程计时器:只要修改代码使用多线程计时器即可:
//使用多线程计时器
privateSystem.Timers.Timertimer=newSystem.Timers.Timer();
publicForm1()
InitializeComponent();
timer.Elapsed+=newSystem.Timers.ElapsedEventHandler(timer_Elapsed);
timer.Enabled=
voidtimer_Elapsed(objectsender,System.Timers.ElapsedEventArgse)
//模拟的做一些耗时的操作
System.Threading.Thread.Sleep(2000);
上面的例子告诉我们单线程计时器的缺点:
除非Tick事件的处理代码执行的非常快,否则UI界面会变得响应很慢。
所以 WPF和Windows Forms的计时器都非常适合小任务,尤其是界面更新的任务。例如时钟和计数显示。否则,你需要一个多线程计时器。
设为1000,再设一个变量每次加1.加12次后做你要做的事,这样就准了.
&上面是2种自己使用一下,感觉那个好就可以了。&
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:81049次
积分:1270
积分:1270
排名:第17316名
原创:42篇
转载:34篇
(2)(6)(4)(3)(5)(3)(1)(5)(5)(7)(4)(4)(2)(1)(1)(6)(6)(11)java定时执行一个方法_百度知道
java定时执行一个方法
java中设置定时任务用Timer类可以实现。  一、延时执行  首先,我们定义一个类,给它取个名字叫TimeTask,我们的定时任务,就在这个类的main函数里执行。代码如下:    import java.util.T  public class TimeTask {   public static void main(String[] args){  Timer timer = new Timer();  timer.schedule(new Task(), 60 * 1000);  }  }  解释一下上面的代码。  上面的代码实现了这样一个功能,当TimeTask程序启动以后,过一分钟后执行某项任务。很简单吧:先new一个Timer对象,然后调用它的schedule方法,这个方法有四个重载的方法,这里我们用其中一个,   public void schedule(TimerTask task,long delay)  首先,第一个参数  第一个参数就是我们要执行的任务。  这是一个TimerTask对象,确切点说是一个实现TimerTask的类的对象,因为TimerTask是个抽象类。上面的代码里面,Task就是我们自己定义的实现了TimerTask的类,因为是在同一个包里面,所以没有显性的import进来。Task类的代码如下     import java.util.TimerT  public class Task extends TimerTask {  public void run(){  System.out.println(&定时任务执行&);  }  }  我们的Task必须实现TimerTask的方法run,要执行的任务就在这个run方法里面,这里,我们只让它往控制台打一行字。   第二个参数  第二个参数是一个long型的值。这是延迟的时间,就是从程序开始以后,再过多少时间来执行定时任务。这个long型的值是毫秒数,所以前面我们的程序里面,过一分钟后执行用的参数值就是 60 * 1000。  二、循环执行  设置定时任务的时候,往往我们需要重复的执行这样任务,每隔一段时间执行一次,而上面的方法是只执行一次的,这样就用到了schedule方法的是另一个重载函数  public void schedule(TimerTask task,long delay,long period)   前两个参数就不用说什么了,最后一个参数就是间隔的时间,又是个long型的毫秒数(看来java里涉及到时间的,跟这个long是脱不了干系了),比如我们希望上面的任务从第一次执行后,每个一分钟执行一次,第三个参数值赋60 * 1000就ok了。  三、指定执行时间  既然号称是定时任务,我们肯定希望由我们来指定任务指定的时间,显然上面的方法就不中用了,因为我们不知道程序什么时间开始运行,就没办法确定需要延时多少。没关系,schedule四个重载的方法还没用完呢。用下面这个就OK了:   public void schedule(TimerTask task,Date time)  比如,我们希望定时任务日0时0分执行,只要给第二个参数传一个时间设置为日0时0分的Date对象就可以了。  有一种情况是,可能我们的程序启动的时候,已经是日了,这样的话,程序一启动,定时任务就开始执行了。  schedule最后一个重载的方法是  public void schedule(TimerTask task,Date firstTime,long period)
其他类似问题
为您推荐:
提问者采纳
在能想到的是三种方法能实现,通过sleep方法来达到定时任务的效果:1。希望能帮到你、普通thread实现 。2。3,以便设定执行的时间间隔等:是最常见的、TimerTask ,创建一个thread,可以很灵活的去设定第一次执行任务delay时间,第一次执行任务时可以指定你想要的delay时间,相比于Timer的单线程,它是通过线程池的方式来执行任务的,提供了良好的约定、ScheduledExecutorService实现 :启动和去取消任务时可以控制,然后让它在while循环里一直运行着:最理想的定时任务实现方式
我遇到了个问题:我现在已经实现了jsp里一个按钮,点击按钮进入action的一个方法,然后Dao方法操作数据库.我现在想用定时执行,我怎么在一个普通类里调用这个action方法呢??action方法:public void checkData(){
System.out.println(&执行校验测试...&);
ips.checkData();}
  用最简单的方法thread来模拟一个定时任务,代码贴你看看:  public class TestRank {  private static class Tasks implements Runnable{//定时任务的线程类  public void run() {  // TODO Auto-generated method stub  while(true){  try {  Thread.sleep(2000); //睡眠2000后再次执行任务,模拟定时任务  System.out.println(&设置定时时间后再次启动任务计划&); //执行任务  } catch (InterruptedException e) {  // TODO Auto-generated catch block  e.printStackTrace();  }  }  }
  }  public static void main(String[] args) {  Tasks tasks = new Tasks();  Thread t = new Thread(tasks);  t.start(); //启动线程(相当于点击了jsp页面上的按钮)  }  }
提问者评价
其他3条回答
Timer 定时器测试
MyTask.java:
package com.
ort java.text.SimpleDateF
import java.util.D
import java.util.TimerT
public class MyTask extends TimerTask{
SimpleDateFormat sdf = new SimpleDateFormat(&yyyy-MM-dd HH:mm:ss&);
public void run(){
System.out.println(sdf.format(new Date()));
TestTimer.java:
package com.
import java.util.T
public class TestTimer{
public static void main(String[] args){
MyTask myTask = new MyTask();
Timer timer = new Timer();
timer.schedule(myTask, ...
Timer类spring间接调用的Timer类,来实现的定时任务
我现在已经实现了jsp里一个按钮,点击按钮进入action的一个方法,然后Dao方法操作数据库.我现在想用定时执行,我怎么在一个普通类里调用这个action方法呢??action方法:public void checkData(){
System.out.println(&执行校验测试...&);
ips.checkData();}
能不能上点工业级别的推荐啊。这方面quartz无出其右啊
java的相关知识
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁Java语言中Timer类的简洁用法_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
评价文档:
Java语言中Timer类的简洁用法
T​i​m​e​r​类​的​简​洁​用​法
阅读已结束,如果下载本文需要使用
想免费下载本文?
把文档贴到Blog、BBS或个人站等:
普通尺寸(450*500pix)
较大尺寸(630*500pix)
你可能喜欢Java中的Timer和Timer Task详解
Java中的Timer和Timer Task详解
  如果你使用Java语言进行开发,对于定时执行任务这样的需求,自然而然会想到使用Timer和TimerTask完成任务,我最近就使用 Timer和TimerTask完成了一个定时执行的任务,实现得没有问题,但当在TimerTaks的run()方法中使用 Thread.sleep()方式时,可能会出现奇怪的现象,好像Timer失效了,网上查了一下,倒是有人遇到了相同的问题,但是并没有找到一篇解释为什么会出现这种情况,期待有某位达人能够分析清楚这个问题。&&& 遇到了这样的问题,始终让我不爽,于是看了一下Timer的源码,先将了解到的内容整理如下,接下来再看看Thread.sleep()的源码,看能否找到问题所在。&&& 在Java中,与定时任务执行相关的类很少,只有Timer、TimerTask、TimerThread、TaskQueue几个,其中每个类的职责大致如下:&&& Timer:一个Task的调度类,和TimerTask一样,暴露给最终用户使用的类,通过schedule方法安排Task的执行计划。该类通过TaskQueue和TimerThread类完成Task的调度。&&& TimerTask:实现Runnable接口,表明每一个任务均为一个独立的线程。通过run()方法提供用户定制自己任务。该类有一个比较重要的成员变量nextExecutionTime ,表示下一次执行该任务的时间。以后会看到,Timer机制就是靠这个值安排Task执行的。&&& TimerThread:继承于Thread,是真正执行Task的类。&&& TaskQueue:一个存储Task的数据结构,内部由一个最小堆实现,堆的每个成员为一个TimeTask,每个Task依靠其 nextExecutionTime值进行排序,也就是说,nextExecutionTime最小的任务在队列的最前端,从而能够现实最早执行。&&& 要想使用Timer,用户只需要了解Timer和TimerTask,下面现已一个最基本的Timer和TimerTask使用案例入手,来看一下Timer内部的实现原理。&&& 01&&& import java.util.T&&& 02&&& 03&&& import java.util.TimerT&&& 04&&& 05&&& import org.junit.T&&& 06&&& 07&&& 08&&& 09&&& class TestTimerTask extends TimerTask {&&& 10&&& 11&&& @Override&&& 12&&& 13&&& public void run() {&&& 14&&& 15&&& System.out.println("TestTimerTask is running……");&&& 16&&& 17&&& }&&& 18&&& 19&&& }&&& 20&&& 21&&& public class TimerTaskTest {&&& 22&&& 23&&& @Test&&& 24&&& 25&&& public void testTimerTask() {&&& 26&&& 27&&& Timer timer = new Timer();&&& 28&&& 29&&& timer.schedule(new TestTimerTask(), 0, 10);&&& 30&&& 31&&& }&&& 32&&& 33&&& }&&& 上面的代码是一个典型的Timer&TimerTask的应用,下面先来看一下new Timer()干了什么事,其源码如下:&&& public Timer(String name) {&&& thread.setName(name);&&& //thread为TimerThread实例。&&& thread.start();&&& }&&& 从上面的源代码可以知道,创建Timer对象的同时也启动了TimerThread线程。下面来看看TimerThread干了什么事:&&& 01&&& public void run() {&&& 02&&& 03&&& try {&&& 04&&& 05&&& mainLoop();&&&&&&&&&&&&&&&& //线程真正执行的代码在这个私有方法中&&& 06&&& 07&&& } finally {&&& 08&&& 09&&& // Someone killed this Thread, behave as if Timer cancelled&&& 10&&& 11&&& synchronized(queue) {&&& 12&&& 13&&& newTasksMayBeScheduled =&&& 14&&& 15&&& queue.clear();& // Eliminate obsolete references&&& 16&&& 17&&& }&&& 18&&& 19&&& }&&& 20&&& 21&&& }&&& 接着来看看私有方法mainLoop()干了什么事:&&& 01&&& private void mainLoop() {&&& 02&&& 03&&& while (true) {&&& 04&&& 05&&& try {&&& 06&&& 07&&& TimerT&&& 08&&& 09&&& boolean taskF&&&&&& //是否已经到达Task的执行时间,如果已经到达,设置为true,否则置为false&&& 10&&& 11&&& synchronized(queue) {&&& 12&&& 13&&& // Wait for queue to become non-empty&&& 14&&& 15&&& while (queue.isEmpty() && newTasksMayBeScheduled)&&& 16&&& 17&&& queue.wait();&&&&&&&&&&&&&&& //由此可以看出,Timer通过wait & notify 方法安排线程之间的同步&&& 18&&& 19&&& if (queue.isEmpty())&&& 20&&& 21&&& // Queue is empty and die&&& 22&&& 23&&& 24&&& 25&&& // Q look at first evt and do the right thing&&& 26&&& 27&&& long currentTime, executionT&&& 28&&& 29&&& task = queue.getMin();&&& 30&&& 31&&& synchronized(task.lock) {&&& 32&&& 33&&& if (task.state == TimerTask.CANCELLED) {&&& 34&&& 35&&& queue.removeMin();&&& 36&&& 37&&&& // No action required, poll queue again&&& 38&&& 39&&& }&&& 40&&& 41&&& currentTime = System.currentTimeMillis();&&& 42&&& 43&&& executionTime = task.nextExecutionT&&& 44&&& 45&&& if (taskFired = (executionTime&=currentTime)) {&&&&&&& //Task的执行时间已到,设置taskFired为true&&& 46&&& 47&&& if (task.period == 0) { // Non-repeating, remove&&& 48&&& 49&&& queue.removeMin();&&&&&&& //移除队列中的当前任务&&& 50&&& 51&&& task.state = TimerTask.EXECUTED;&&& 52&&& 53&&& } else { // Repeating task, reschedule&&& 54&&& 55&&& queue.rescheduleMin(&&&&&&&& //重新设置任务的下一次执行时间&&& 56&&& 57&&& task.period&0 ? currentTime&& - task.period&&& 58&&& 59&&& : executionTime + task.period);&&& 60&&& 61&&& }&&& 62&&& 63&&& }&&& 64&&& 65&&& }&&& 66&&& 67&&& if (!taskFired) // Task hasn' wait&&& 68&&& 69&&& queue.wait(executionTime - currentTime);&&& //还没有执行时间,通过wait等待特定时间&&& 70&&& 71&&& }&&& 72&&& 73&&& if (taskFired)& // T run it, holding no locks&&& 74&&& 75&&& task.run();&&& //已经到达执行时间,执行任务&&& 76&&& 77&&& } catch(InterruptedException e) {&&& 78&&& 79&&& }&&& 80&&& 81&&& }&&& 82&&& 83&&& }&&& 也就是说,一旦创建了Timer类的实例,就一直存在一个循环在遍历queue中的任务,如果有任务的话,就通过thread去执行该任务,否则线程通过wait()方法阻塞自己,由于没有任务在队列中,就没有必要继续thread中的循环。
  上面提到,如果Timer的任务队列中不包含任务时,Timer中的TimerThread线程并不会执行,接着来看看为Timer添加任务后会出现怎样的情况。为Timer添加任务就是timer.schedule()干的事,schedule()方法直接调用Timer的私有方法 sched(),sched()是真正安排Task的地方,其源代码如下:&&& 01&&& private void sched(TimerTask task, long time, long period) {&&& 02&&& 03&&& if (time & 0)&&& 04&&& 05&&& throw new IllegalArgumentException("Illegal execution time.");&&& 06&&& 07&&& 08&&& 09&&& synchronized(queue) {&&& 10&&& 11&&& if (!thread.newTasksMayBeScheduled)&&& 12&&& 13&&& throw new IllegalStateException("Timer already cancelled.");&&& 14&&& 15&&& 16&&& 17&&& synchronized(task.lock) {&&& 18&&& 19&&& if (task.state != TimerTask.VIRGIN)&&&&&&&&&&&& //我喜欢virgin状态,其他状态表明该Task已经被schedule过了&&& 20&&& 21&&& throw new IllegalStateException(&&& 22&&& 23&&& "Task already scheduled or cancelled");&&& 24&&& 25&&& 26&&& 27&&& //设置Task下一次应该执行的时间, 由System.currentTimeMillis()+/-delay得到&&& 28&&& 29&&& task.nextExecutionTime =&&& 30&&& 31&&& task.period =&&& 32&&& 33&&& task.state = TimerTask.SCHEDULED;&&& 34&&& 35&&& }&&& 36&&& 37&&& 38&&& 39&&& queue.add(task);&&&&&&&&&&& //queue为TaskQueue类的实例,添加任务到队列中&&& 40&&& 41&&& if (queue.getMin() == task)&&&&&&& //获取队列中nextExecutionTime最小的任务,如果与当前任务相同&&& 42&&& 43&&& queue.notify();&&&&&&&&&&&&&&&&&&&&&&&& //还记得前面看到的queue.wait()方法么&&& 44&&& 45&&& }&&& 46&&& 47&&& }&&& 不要奇怪,为什么要判断queue.getMin() == task时,才通过queue.notify()恢复执行。因为这种方式已经满足所有的唤醒要求了。&&& 如果安排当前Task之前queue为空,显然上述判断为true,于是mainLoop()方法能够继续执行。&&& 如果安排当前Task之前queue不为空,那么mainLoop()方法不会一直被阻塞,不需要notify方法调用。&&& 调用该方法还有一个好处是,如果当前安排的Task的下一次执行时间比queue中其余Task的下一次执行时间都要小,通过notify方法可以提前打开queue.wait(executionTime - currentTime)方法对mainLoop()照成的阻塞,从而使得当前任务能够被优先执行,有点抢占的味道。&&& 上述分析可以看出,Java中Timer机制的实现仅仅使用了JDK中的方法,通过wait & notify机制实现,其源代码也非常简单,但可以想到的是这种实现机制会对开发者造成一种困扰,sched()方法中可以看出,对于一个重复执行的任务,Timer的实现机制是先安排Task下一次执行的时间,然后再启动Task的执行,如果Task的执行时间大于下一次执行的间隔时间,可能出现不可预期的错误。当然,了解了Timer的实现原理,修改这种实现方式也就非常简单了。&&& java Timer 使用详解&&& 在应用开发中,经常需要一些周期性的操作,比如每5分钟检查一下新邮件等。对于这样的操作最方便、高效的实现方式就是使用java.util.Timer工具类。比如下面的代码每5分钟检查一遍是否有新邮件:&&& private& java.util.Timer&&&& timer = new& Timer (true );&&& timer.schedule(new& java.util.TimerTask () {&&& public& void& run() {&&& //server.checkNewMail(); 检查新邮件&&& }&&& }, 0, 5*60*1000);&&& 使用这几行代码之后,Timer本身会每隔5分钟调用一遍server.checkNewMail()方法,不需要自己启动线程。Timer本身也是多线程同步的,多个线程可以共用一个Timer,不需要外部的同步代码。&&& 在《The Java Tutorial》中有更完整的例子:&&& public& class& AnnoyingBeep {&&& Toolkit&&&& Timer&&&& public& AnnoyingBeep() {&&& toolkit = Toolkit .getDefaultToolkit();&&& timer = new& Timer ();&&& timer.schedule(new& RemindTask(),&&& 0,&&&&&&& //initial delay&&& 1*1000);& //subsequent rate&&& }&&& class& RemindTask extends& TimerTask& {&&& int& numWarningBeeps = 3;&&& public& void& run() {&&& if& (numWarningBeeps & 0) {&&& toolkit.beep();&&& System .out.println("Beep!" );&&& numWarningBeeps--;&&& } else& {&&& toolkit.beep();&&& System .out.println("Time's up!" );&&& //timer.cancel(); //Not necessary because we call System.exit&&& System .exit(0);&& //Stops the AWT thread (and everything else)&&& }&&& }&&& }&&& …&&& }&&& 这段程序,每隔3秒响铃一声,并打印出一行消息。循环3次。程序输出如下:&&& Task scheduled.&&& Beep!&&& Beep!&&&&& //one second after the first beep&&& Beep!&&&&& //one second after the second beep&&& Time's up! //one second after the third beep&&& Timer类也可以方便地用来作为延迟执行,比如下面的代码延迟指定的时间(以秒为单位)执行某操作。类似电视的延迟关机功能。&&& …&&& public& class& ReminderBeep {&&& …&&& public& ReminderBeep(int& seconds) {&&& toolkit = Toolkit .getDefaultToolkit();&&& timer = new& Timer ();&&& timer.schedule(new& RemindTask(), seconds*1000);&&& }&&& class& RemindTask extends& TimerTask& {&&& public& void& run() {&&& System .out.println("Time's up!" );&&& toolkit.beep();&&& //timer.cancel(); //Not necessary because we call System.exit&&& System .exit(0);&& //Stops the AWT thread (and everything else)&&& }&&& }&&& …&&& }
  一些注意的问题:&&& 1. 如果希望自己的Task一直运行,而不是像上面的RemindTask那样仅循环3次。&&& 这 很简单,Task仅代表了一次的动作。而不是让Task完成循环。上面的RemindTask中之所以有一个计数,是因为要运行3次停止,如果需要一直保 持运行。把上面有关的计数的代码全部去除即可。其实Timer中并没有提供运行指定次数后即停止的机制,所以,上面的计数满足了这个功能需要。&&& 2. 能否设置Timer的优先级?&&& Timer 中是利用一个线程来进行计时及周期触发动作的。现在的Timer实现中并没有提供设置优先级的方法,在你调用new Timer()时线程已经启动,所 以,除非Timer的以后版本中在构造方法中增加优先级参数,否则,我们是不能控制其优先级的。现在的Timer默认是在 Thread.NORM_PRIORITY优先级下运行的。但是Timer提供了一个Timer(boolean isDaemon)的构造方法,可以将 Timer设置为daemon线程。这样,在你的程序中其它线程都运行完毕后,程序就可以退出了。&&& 3. Timer是不是实现了精确地定时?&&& 否。Timer中也是采用Object.wait(long time)来实现定时的,由于Object.wait()不保证精确计时,所以Timer也不是一个精确的时钟。如果是实时系统,不能依赖Timer.&&& 4. 假如在一个Timer类里面再定义一个Timer类,外层定义的时间是24小时循环一次,而内层定义的是1小时循环一次,意思就是当一个小时内层运行完一次之后,内层Timer释放资源,那么外层的Timer是不是也会释放,还是24小时之中一直都在占用?&&& 不 太清楚此占用资源是什么意思,如果在Task中用到一些资源,这些资源应该在Task运行结束后即刻释放,尤其对竞态条件,更应该占用尽量少的时间。一般 来说,一次Task的运行时间,将少于你设定的周期。否则,Task将在Timer中堆积起来。如果要实现上面说的每24小时和每1小时两个周期的操作, 可以使用一个Timer,schedule两个Task即可。&&& 5. Timer是否可以在多线程环境下使用?&&& 可以。Timer中用于存储Task的容器是同步了的,保证了多线程环境先的安全使用。&&& 6. 定时的时间能为变量,可以在程序中变化吗?就是说定时的时间可以又界面来控制。&&& 一 个Timer可以控制任意多个Task的不同周期设定的触发。也就是说,这个Timer类似于可以定多个时间的闹钟,比如我的手机就有3个闹 钟 :)& .但是一旦一个Task 已经进行了schedule了,那么就不能再次进行设定。所以,也不可能再改变其周期、延迟等等设定了。可以看下面 的代码:&&& synchronized (task.lock) {&&& if& (task.state != TimerTask .VIRGIN)&&& throw& new& IllegalStateException (&&& "Task already scheduled or cancelled" );&&& task.nextExecutionTime =&&& task.period =&&& task.state = TimerTask .SCHEDULED;&&& }&&& 7. 可不可以认为Timer就是一个线程的发射器?&&& Timer中仅有一个存储Task的Queue和一个调度所有Task的线程。不管你schedule几次,在Timer上加了几个Task,都只有一个后台的线程进行调度。
&&&主编推荐
H3C认证Java认证Oracle认证
基础英语软考英语项目管理英语职场英语
.NETPowerBuilderWeb开发游戏开发Perl
二级模拟试题一级模拟试题一级考试经验四级考试资料
港口与航道工程建设工程法规及相关知识建设工程经济考试大纲矿业工程市政公用工程通信与广电工程
操作系统汇编语言计算机系统结构人工智能数据库系统微机与接口
软件测试软件外包系统分析与建模敏捷开发
法律法规历年试题软考英语网络管理员系统架构设计师信息系统监理师
高级通信工程师考试大纲设备环境综合能力
路由技术网络存储无线网络网络设备
CPMP考试prince2认证项目范围管理项目配置管理项目管理案例项目经理项目干系人管理
Powerpoint教程WPS教程
电子政务客户关系管理首席信息官办公自动化大数据
职称考试题目
就业指导签约违约职业测评
招生信息考研政治
网络安全安全设置工具使用手机安全
3DMax教程Flash教程CorelDraw教程Director教程
Dreamwaver教程HTML教程网站策划网站运营Frontpage教程
生物识别传感器物联网传输层物联网前沿技术物联网案例分析
互联网电信IT业界IT生活
Java核心技术J2ME教程
Linux系统管理Linux编程Linux安全AIX教程
Windows系统管理Windows教程Windows网络管理Windows故障
组织运营财务资本
视频播放文件压缩杀毒软件输入法微博
数据库开发Sybase数据库Informix数据库
&&&&&&&&&&&&&&&
希赛网 版权所有 & &&&&湘教QS2-164&&增值电信业务经营许可证湘B2-}

我要回帖

更多关于 java timer 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信