定时器 实现
private java.util.Timer timer;
timer = new Timer(true);
timer.schedule(
new java.util.TimerTask() { public void run() { //server.checkNewMail(); 檢查新郵件 } }, 0, 5*60*1000);
??? 使用這幾行代碼之后,Timer本身會每隔5分鐘調(diào)用一遍server.checkNewMail()方法,不需要自己啟動線程。Timer本身也是多線程同步的,多個線程可以共用一個Timer,不需要外部的同步代碼。
在《The Java Tutorial》中有更完整的例子:
public class AnnoyingBeep {
Toolkit toolkit;
?Timer timer;?
?public AnnoyingBeep() {
??toolkit = Toolkit.getDefaultToolkit();
??timer = new Timer();
??timer.schedule(new RemindTask(), 0, 1*1000);
//initial delay??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秒響鈴一聲,并打印出一行消息。循環(huán)3次。程序輸出如下:
IWAV0048I Java Bean com.AnnoyingBeep started with null constructor
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類也可以方便地用來作為延遲執(zhí)行,比如下面的代碼延遲指定的時間(以秒為單位)執(zhí)行某操作。類似電視的延遲關(guān)機功能。
...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)
???}
??}
?...
?}
}
????下面就Servlet偵聽器結(jié)合Java定時器來講述整個實現(xiàn)過程。要運用Servlet偵聽器需要實現(xiàn)javax.servlet.ServletContextListener接口,同時實現(xiàn)它的contextInitialized(ServletContextEvent?event)和contextDestroyed(ServletContextEvent?event)兩個接口函數(shù)。考慮定時器有個建立和銷毀的過程,看了前面兩個接口函數(shù),就不容置疑的把建立的過程置入contextInitialized,把銷毀的過程置入contextDestroyed了。
????我把ServletContextListener的實現(xiàn)類取名為ContextListener,在其內(nèi)添加一個定時器,示例代碼如下所示(為考慮篇幅,僅提供部分代碼供讀者參考):
????以上代碼中,?timer.schedule(new?MyTask(event.getServletContext()),?0,?60*60*1000)這一行為定時器調(diào)度語句,其中MyTask是自定義需要被調(diào)度的執(zhí)行任務(wù)(在我的財政數(shù)據(jù)中心項目中就是報表計算引擎入口),從java.util.TimerTask繼承,下面會重點講述,第三個參數(shù)表示每小時(即60*60*1000毫秒)被觸發(fā)一次,中間參數(shù)0表示無延遲。其它代碼相當(dāng)簡單,不再詳細說明。
???下面介紹MyTask的實現(xiàn),上面的代碼中看到了在構(gòu)造MyTask時,傳入了javax.servlet.ServletContext類型參數(shù),是為記錄Servlet日志方便而傳入,因此需要重載MyTask的構(gòu)造函數(shù)(其父類java.util.TimerTask原構(gòu)造函數(shù)是沒有參數(shù)的)。在timer.schedule()的調(diào)度中,設(shè)置了每小時調(diào)度一次,因此如果想實現(xiàn)調(diào)度任務(wù)每24小時被執(zhí)行一次,還需要判斷一下時鐘點,以常量C_SCHEDULE_HOUR表示(晚上12點,也即0點)。同時為防止24小時執(zhí)行下來,任務(wù)還未執(zhí)行完(當(dāng)然,一般任務(wù)是沒有這么長的),避免第二次又被調(diào)度以引起執(zhí)行沖突,設(shè)置了當(dāng)前是否正在執(zhí)行的狀態(tài)標(biāo)志isRunning。示例代碼如下所示:
????上面代碼中“//TODO……”之下四行是真正被調(diào)度執(zhí)行的演示代碼(在我的財政數(shù)據(jù)中心項目中就是報表計算過程),您可以換成自己希望執(zhí)行的語句。
???? 到這兒,ServletContextListener和MyTask的代碼都已完整了。最后一步就是把ServletContextListener部署到您的Web工程中去,在您工程的web.xml配置文件中加入如下三行:
????
???????? com.test.ContextListener
????
????當(dāng)然,上面的com.test得換成您自己的包名了。保存web.xml文件后,把工程打包部署到Tomcat中即可。任務(wù)會在每晚12點至凌晨1點之間被執(zhí)行,上面的代碼會在Tomcat的日志文件中記錄如下:
2003-12-05?0:21:39?開始執(zhí)行指定任務(wù)
2003-12-05?0:21:39?已完成任務(wù)的1/10
????……
2003-12-05?0:21:39?已完成任務(wù)的10/10
2003-12-05?0:21:39?指定任務(wù)執(zhí)行結(jié)束
由于系統(tǒng)核心是基于Web部署的,報表計算引擎也相應(yīng)的部署在Tomcat容器上,因此如果想要借用Windows的任務(wù)計劃來實現(xiàn)定時計算,就需要額外編寫普通桌面應(yīng)用程序接口,稍顯復(fù)雜。于是就琢磨著想在Web上實現(xiàn),經(jīng)過查閱較多相關(guān)資料,發(fā)現(xiàn)Java定時器(java.util.Timer)有定時觸發(fā)計劃任務(wù)的功能,通過配置定時器的間隔時間,在某一間隔時間段之后會自動有規(guī)律的調(diào)用預(yù)先所安排的計劃任務(wù)(java.util.TimerTask)。另外,由于我們希望當(dāng)Web工程啟動時,定時器能自動開始計時,在整個Web工程的生命期里,定時器能在每晚深夜觸發(fā)一次報表計算引擎。因此定時器的存放位置也值得考查,不能簡單的存在于單個Servlet或JavaBean中,必須能讓定時器宿主的存活期為整個Web工程生命期,在工程啟動時能自動加載運行。結(jié)合這兩點,跟Servlet上下文有關(guān)的偵聽器就最合適不過了,通過在工程的配置文件中加以合理配置,會在工程啟動時自動運行,并在整個工程生命期中處于監(jiān)聽狀態(tài)。
????下面就Servlet偵聽器結(jié)合Java定時器來講述整個實現(xiàn)過程。要運用Servlet偵聽器需要實現(xiàn)javax.servlet.ServletContextListener接口,同時實現(xiàn)它的contextInitialized(ServletContextEvent?event)和contextDestroyed(ServletContextEvent?event)兩個接口函數(shù)。考慮定時器有個建立和銷毀的過程,看了前面兩個接口函數(shù),就不容置疑的把建立的過程置入contextInitialized,把銷毀的過程置入contextDestroyed了。
????我把ServletContextListener的實現(xiàn)類取名為ContextListener,在其內(nèi)添加一個定時器,示例代碼如下所示(為考慮篇幅,僅提供部分代碼供讀者參考):
????以上代碼中,?timer.schedule(new?MyTask(event.getServletContext()),?0,?60*60*1000)這一行為定時器調(diào)度語句,其中MyTask是自定義需要被調(diào)度的執(zhí)行任務(wù)(在我的財政數(shù)據(jù)中心項目中就是報表計算引擎入口),從java.util.TimerTask繼承,下面會重點講述,第三個參數(shù)表示每小時(即60*60*1000毫秒)被觸發(fā)一次,中間參數(shù)0表示無延遲。其它代碼相當(dāng)簡單,不再詳細說明。
???下面介紹MyTask的實現(xiàn),上面的代碼中看到了在構(gòu)造MyTask時,傳入了javax.servlet.ServletContext類型參數(shù),是為記錄Servlet日志方便而傳入,因此需要重載MyTask的構(gòu)造函數(shù)(其父類java.util.TimerTask原構(gòu)造函數(shù)是沒有參數(shù)的)。在timer.schedule()的調(diào)度中,設(shè)置了每小時調(diào)度一次,因此如果想實現(xiàn)調(diào)度任務(wù)每24小時被執(zhí)行一次,還需要判斷一下時鐘點,以常量C_SCHEDULE_HOUR表示(晚上12點,也即0點)。同時為防止24小時執(zhí)行下來,任務(wù)還未執(zhí)行完(當(dāng)然,一般任務(wù)是沒有這么長的),避免第二次又被調(diào)度以引起執(zhí)行沖突,設(shè)置了當(dāng)前是否正在執(zhí)行的狀態(tài)標(biāo)志isRunning。示例代碼如下所示:
????上面代碼中“//TODO……”之下四行是真正被調(diào)度執(zhí)行的演示代碼(在我的財政數(shù)據(jù)中心項目中就是報表計算過程),您可以換成自己希望執(zhí)行的語句。
???? 到這兒,ServletContextListener和MyTask的代碼都已完整了。最后一步就是把ServletContextListener部署到您的Web工程中去,在您工程的web.xml配置文件中加入如下三行:
???
web.xml 里面<listener>
<listener-class>com.bean.statListener</listener-class>
</listener>
?????
????當(dāng)然,上面的com.test得換成您自己的包名了。保存web.xml文件后,把工程打包部署到Tomcat中即可。任務(wù)會在每晚12點至凌晨1點之間被執(zhí)行,上面的代碼會在Tomcat的日志文件中記錄如下:
2003-12-05?0:21:39?開始執(zhí)行指定任務(wù)
2003-12-05?0:21:39?已完成任務(wù)的1/10
????……
2003-12-05?0:21:39?已完成任務(wù)的10/10
2003-12-05?0:21:39?指定任務(wù)執(zhí)行結(jié)束
3、實現(xiàn)定時
public ? class ? myTask ?
? ? ? ? ? extends ? java.util.TimerTask ? { ?
? ? ? String ? jobName; ?
? ? ? private ? int ? i; ?
? ? ? public ? void ? run() ? { ? //run ? in ? interface ? Runnable ?
? ? ? ? ? System.out.println(jobName); ?
? ? ? } ?
? ?
? ? ? public ? myTask(String ? jobName) ? { ?
? ? ? ? ? this.jobName ? = ? jobName; ?
? ? ? } ?
? } ?
? ?
? //doTask.java ? ?
? ?
? import ? java.util.*; ?
? import ? java.io.*; ?
? ?
? public ? class ? doTask ? { ?
? ? ? private ? java.util.Timer ? timer; ?
? ? ? private ? java.util.TimerTask ? task; ?
? ? ? public ? doTask(java.util.TimerTask ? task) ? { ?
? ? ? ? ? this.timer ? = ? new ? Timer(); ?
? ? ? ? ? this.task ? = ? task; ?
? ? ? } ?
? ? ? public ? void ? start(int ? delay, ? int ? internal) ? { ?
? ? ? ? ? timer.schedule(task, ? delay ? * ? 1000, ? internal ? * ? 1000);//利用timer.schedule方法 ?
? ? ? } ?
? ?
? ? ? public ? static ? void ? main(String[] ? args) ? { ?
? ? ? ? ? java.util.TimerTask ? task1 ? = ? new ? myTask(" ? ? ? ? ? Job ? 1"); ?
? ? ? ? ? java.util.TimerTask ? task2= ? new ? myTask("Job ? 2"); ?
? ? ? ? ? doTask ? pt ? = ? new ? doTask(task1); ?
? ? ? ? ? pt.start(1,3); ?
? ? ? ? ? doTask ? pt2 ? = ? new ? doTask(task2); ?
? ? ? ? ? pt2.start(1,1); ?
? ? ? } ?
? ?
? }??
4、C#結(jié)合singleton和線程做一個定時服務(wù)
design pattern的singleton是一個雖然簡單但很有用處的模式,它的作用就是使類只能有一個實例,不需要實例化,而提供一個唯一的全局切入點。如果再結(jié)合上線程,完全可以實現(xiàn)一個定時服務(wù),不象Timer控件,它不僅可以應(yīng)用在windows應(yīng)用程序中,同樣可以應(yīng)用于web程序中,就象剛才藍說的那種效果。看下面這個簡單的例子吧。
using System;
using System.Threading ;
namespace testall
{
/// <summary>
/// 定時間隔
/// </summary>
/// <remarks>通過修改這個常量決定間隔多長時間做某件事</remarks>
const int DELAY_TIMES = 1000 ;
/// <summary>
/// 一個計數(shù)器
/// </summary>
private int m_intCounter = 0;
/// <summary>
/// 是否退出
/// </summary>
private bool m_bCanExit = false ;
/// <summary>
/// 線程
/// </summary>
private Thread thread ;
/// <summary>
/// 自身實例
/// </summary>
/// <remarks>注意,這是實現(xiàn)singleton的關(guān)鍵</remarks>
private static TestStatic instance = new TestStatic() ;
public int Counter
{
get
{
return this.m_intCounter ;
}
set
{
this.m_intCounter = value ;
}
}
public bool CanExit
{
set
{
this.m_bCanExit = value ;
}
}
/// <summary>
/// 構(gòu)造函數(shù)
/// </summary>
public TestStatic()
{
//
// TODO: Add constructor logic here
//
this.m_intCounter = 0 ;
Console.WriteLine("constructor is running") ;
this.thread = new Thread(new ThreadStart(ThreadProc)) ;
thread.Name = "online user" ;
thread.Start() ;
Console.WriteLine("完畢") ;
}
/// <summary>
/// 實現(xiàn)singleton的關(guān)鍵
/// </summary>
/// <returns>類本身的一個實例</returns>
/// <remarks>唯一的全局切入點</remarks>
public static TestStatic GetInstance()
{
return instance ;
}
/// <summary>
/// 線程工作函數(shù)
/// </summary>
/// <remarks>想做什么寫在這兒</remarks>
private void ThreadProc()
{
while(!this.m_bCanExit)
{
this.m_intCounter ++ ;
Console.WriteLine(this.m_intCounter.ToString()) ;
Thread.Sleep(DELAY_TIMES) ;
}
}
static void Main(string[] args)
{
//
// TODO: Add code to start application here
//
Console.WriteLine(TestStatic.GetInstance().Counter.ToString()) ;
Console.Read() ;
TestStatic.GetInstance().CanExit = true ;
}
}
}
//
import?java.util.TimerTask;??
import?java.util.Calendar;??
public?class?MyTask?extends?TimerTask?
{??
????private?static?final?int?C_SCHEDULE_HOUR?=?15;??
????private?static?boolean?isRunning?=?false;??
????public?MyTask()?
????{??
????}??
????public?void?run()?
????{??
????????Calendar?cal?=?Calendar.getInstance();??
????????if?(!isRunning)?
????????{??
????????????//if?(C_SCHEDULE_HOUR?==?cal.get(Calendar.HOUR_OF_DAY))?
????????????{??
????????????????isRunning?=?true;??
????????????????System.out.println(new?java.util.Date()?+?"????????任務(wù)開始");??
????????????????for?(int?i?=?0?;?i?<?100?;?i++?)?
????????????????{?
????????????????????System.out.println(new?java.util.Date()?+?"??????????任務(wù)完成"?+?i?+?"/"?+?100?);??
????????????????}??
????????????????isRunning?=?false;??
????????????????System.out.println(new?java.util.Date()?+?"???????所有任務(wù)完成!");??
????????????}??
????????}??
????????else??
????????{??
????????????System.out.println(new?java.util.Date()?+?"?????????任務(wù)退出!!!");??
????????}??
????}??
}?
=====================================Test===========================================?
import?java.util.TimerTask;?
import?java.util.Timer;??
import?javax.servlet.*;?
public?class?Test{?
????static?Timer?timer?=?null;?
????public?static?void?main(String[]?args){?
????????timer?=?new?Timer(true);?
????????System.out.println(new?java.util.Date()?+?"??????計時器已經(jīng)啟動...");?
????????timer.schedule(new?MyTask()?,?0?,?2*60*1000);//每2分鐘執(zhí)行一次?
????????System.out.println(new?java.util.Date()?+?"??????????計時器執(zhí)行一次!!!!!");?
????}?
}?
//
| JAVA-如何實現(xiàn)TIMER功能 |
2004-11-8
Author :Meanson Wang
Email:meansonw@hotmail.com
Date:2004-11-8
JAVA里面要實現(xiàn)日程管理[每天或每月的某時執(zhí)行某個任務(wù)],可以用timer和TimerTask來實現(xiàn)。 本文會介紹如何實現(xiàn)一個日程的方法。這里會設(shè)計兩個類,一個偵聽類,用來定時執(zhí)行任務(wù)[可執(zhí)行多個任務(wù)].一個任務(wù)類,用來調(diào)用任務(wù).以下是實現(xiàn)每天15:00執(zhí)行一個任務(wù). 1.listener?class package?timer; import?java.util.TimerTask; import?java.util.Timer; import?javax.servlet.*;? public?class?RemindListener?implements?ServletContextListener?{ private?java.util.Timer?timer?=?null; public?void?contextInitialized(ServletContextEvent?sce)?{ timer?=?new?java.util.Timer(true); sce.getServletContext().log(new?java.util.Date()+"Timer?start?up!"); timer.schedule(new?RemindTask(),0,60*60*1000);//every 60?minute?roll sce.getServletContext().log(new?java.util.Date()+"Schedule?loaded!"); } public?void?contextDestroyed(ServletContextEvent?sce)?{ timer.cancel(); sce.getServletContext().log(new?java.util.Date()+"Timer?destroyed!"); } } 2.Task?class package?timer; import?java.util.TimerTask; import?java.util.Calendar; public?class?RemindTask?extends?TimerTask{ private?static?final?int?C_SCHEDULE_HOUR???=?15; private?static?boolean?isRunning?=?false;????? public?RemindTask()?{ } public?void?run()?{ Calendar?cal?=?Calendar.getInstance(); ?????????if?(!isRunning)??{????????????? ?????????????if?(C_SCHEDULE_HOUR?==?cal.get(Calendar.HOUR_OF_DAY))?{??? ?????????????????isRunning?=?true;???????????? ? ?????????????????System.out.println(new?java.util.Date()+"task?start"); ?? ?????????????????//TODO?for?example ????????int?i?=?0; ????????while?(i++?<?10)?{ ??????System.out.println(new?java.util.Date()+"Done!task"?+?i?+?"/"?+?10); ???????} ?????????????????isRunning?=?false; ????????????? ?????????????????System.out.println(new?java.util.Date()+"All?task?Done!");??????????? ?? ?????????????????} ????????}? ?????????else? ?????????????{ ???????????????System.out.println(new?java.util.Date()+"Task?existed!"); ?????????????} ? } } 3.loadonstart?in?web.xml ????<listener> ????????<listener-class>timer.RemindListener</listener-class> ????</listener> 4.restart?server 注意:當(dāng)您為您的應(yīng)用設(shè)置了虛擬機,定時器會啟動兩個.任務(wù)會執(zhí)行兩次!我的解決方法是為日程管理另起一個應(yīng)用. |
//
使用定時器,定時執(zhí)行任務(wù)
import java.util.Timer;
import java.util.TimerTask;
public class Test
{
??????? public static void main(String args[])
??????? {
??????????????? final Timer timer = new Timer();
??????????????? timer.scheduleAtFixedRate(new TTask(),5000,1000);
??????? }
}
class TTask extends TimerTask
{
??????? public void run()
??????? {
??????????????? System.out.println("hello");
??????? }
}
??在Java中實現(xiàn)Job Scheduling
?在大多數(shù)項目中,在特定的時間或頻率下你需要完成一些特定的任務(wù)。在本文中我們將演示如何用標(biāo)準的Java Timer API來實現(xiàn)。
大多商業(yè)應(yīng)用都會用報表和統(tǒng)計,很難想象沒有這些幫助我們分析未來趨勢的數(shù)據(jù),我們還要這系統(tǒng)干什么。問題是如此多的數(shù)據(jù)我們該如何觸發(fā),如果處理對系統(tǒng)性能影響不大。比較好的方式是避開應(yīng)用高峰,讓服務(wù)器在閑暇時完成這些事。
下面是我的程序:
import java.util.TimerTask;
import java.util.Calendar;
import java.util.Date;
import java.util.Timer;
?
public class ReportGenerator extends TimerTask{
?
??? /* (非 Javadoc)
??? ?* @see java.util.TimerTask#run()
??? ?*/
??? public void run() {
??????? System.out.println("Generating report");
?
???????
??? }
?
}
class MainApplication {
?
? public static void main(String[] args) {
??? Timer timer=new Timer();
??? Calendar date = Calendar.getInstance();
??? date.set(
????? Calendar.DAY_OF_WEEK,
????? Calendar.SUNDAY
??? );
??? date.set(Calendar.HOUR, 0);
??? date.set(Calendar.MINUTE, 0);
??? date.set(Calendar.SECOND, 0);
??? date.set(Calendar.MILLISECOND, 0);
??? // Schedule to run every Sunday in midnight
??? timer.schedule(
????? new ReportGenerator(),
????? date.getTime(),
????? 1000 * 60 * 60 * 24 * 7
??? );
? }
}
我先簡單解釋一下,在我們的例子中ReportGenerator繼承java.util.TimerTask,它又繼承了java.lang.Runnable,我們需要覆蓋run()方法。
調(diào)用時我們用schedule()方法讓它每周日0點0分執(zhí)行,避開服務(wù)器高峰,實現(xiàn)Job Scheduling的目的。
總結(jié)
- 上一篇: 《风起洛阳》数字藏品发售,带你一起梦回神
- 下一篇: mySQL语句整理