JAVA的定時器總結
阿新 • • 發佈:2018-12-24
執行結果: [java] view plaincopyprint?
通過執行結果間隔時間的區別我們很容易區別開這兩個方法的使用。
java的定時器在平時應用到的還是很多的,比如它可以定時清理資料、定時清理快取、定時彈出訊息提示等等。我們現在做的一個專案應用的就比較多,我們主要應用它來監測程式的執行狀態。用的地方這麼多,那就有必要整理一下,翻了翻API,也上網查了查資料,發現了一個問題,網上有些人說Timer類的scheduleAtFixedRate()方法存在著執行緒同步的問題,可是API上介紹的Timer類是執行緒安全類啊。覺得誰的都不敢相信,還是自己驗證一下比較好。
既然已經用到了Timer,那麼就把基礎的用法順便也整理一下,首先寫個最簡單的定時器例子:
[java] view plaincopyprint?- import java.io.IOException;
- import java.text.Format;
- import java.text.ParseException;
- import java.text.SimpleDateFormat;
- import java.util.Date;
- import java.util.Timer;
- import java.util.TimerTask;
- /**
- * Timer是一種執行緒設施,用於安排以後在後臺執行緒中執行的任務。可安排任務執行一次,或者定期重複執行。
- * Timer學習比較簡單,按照API把Timer類中的方法弄懂就夠用了。
- *
- * 此類是執行緒安全的:多個執行緒可以共享單個 Timer 物件而無需進行外部同步。
- * 這一點很重要(即使是使用scheduleAtFixedRate方法的時候碰見延遲問題,也不會出現執行緒同步的問題)
- *
- * schedule()方法有四種引數形式:
- *
- * (1)、void schedule(TimerTask task, Date time) 安排在指定時間執行指定任務(如果傳遞的引數時間已過,則立即執行任務)
- *
- * (2)、void schedule(TimerTask task, long delay) 安排在指定延遲後執行指定任務
- *
- * (3)、void schedule(TimerTask task, Date firstTime, long period) 安排指定的任務在指定的時間開始進行重複的固定延遲執行。
- * 在固定延遲執行中,根據前一次執行的實際執行時間來安排每次執行。如果由於任何原因(如垃圾回收或其他後臺活動)而延遲了某次執行,
- * 則後續執行也將被延遲。從長期來看,執行的週期一般要略大於指定的週期。
- *
- * (4)、schedule(TimerTask task, long delay, long period) 安排指定的任務在指定延遲後開始進行重複的固定延遲執行。
- * <span style="white-space: pre;"> </span>在固定延遲執行中,根據前一次執行的實際執行時間來安排每次執行。如果由於任何原因(如垃圾回收或其他後臺活動)而延遲了某次執行,
- * 則後續執行也將被延遲。從長期來看,執行的週期一般要略大於指定的週期。
- *
- * scheduleAtFixedRate()方法有兩種引數形式
- * 在固定速率執行中,相對於已安排的初始執行時間來安排每次執行。如果由於任何原因(如垃圾回收或其他背景活動)而延遲了某次執行,
- * 則將快速連續地出現兩次或更多次執行,從而使後續執行能夠趕上來。從長遠來看,執行的頻率將正好是指定週期的倒數
- *
- * (1)、 void scheduleAtFixedRate(TimerTask task, Date firstTime, long period) 安排指定的任務在指定的時間開始進行重複的"固定速率"執行。
- *
- * (2)、void scheduleAtFixedRate(TimerTask task, long delay, long period) 安排指定的任務在指定的延遲後開始進行重複的"固定速率"執行。
- *
- * cancel() 方法:終止此計時器,丟棄所有當前已安排的任務。這不會干擾當前正在執行的任務(就是說已經進入run()方法的了就繼續執行,如果還有其他排隊的,那不執行)。
- * <span style="white-space: pre;"> </span> 一旦終止了計時器,那麼它的執行執行緒也會終止,並且無法根據它安排更多的任務。
- *
- * int purge() 從此計時器的任務佇列中移除所有已取消的任務,如果沒有對這些任務的外部引用,則它們就成為垃圾回收的合格物件。 以時間換取了空間。 一般程式不必要用。
- * 返回值是從佇列中移除的任務數。
- *
- */
- publicclass TimerTest {
- publicstaticvoid main(String[] args) throws ParseException {
- final Timer timer = new Timer();
- timer.schedule(new TimerTask(){
- @Override
- publicvoid run() {
- SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
- Date date1=new Date();
- String t1=df.format(date1);//取到格式化後的當前時間
- String t2="2013-12-17 21:00:00";
- Date date2 = null;
- try {
- date2 = df.parse(t2);//將字串轉換成時間格式
- } catch (ParseException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- System.out.println(date1.getTime());
- //指定定時器結束的條件,要不然會該定時器會一直執行下去
- if(date1.getTime()>=date2.getTime()){
- System.out.println(t1+"定時器停止了");
- timer.cancel();//終止該定時器
- }
- }
- }, 1000,2000);// 在1秒後執行此任務,每次間隔2秒
- }
- }
import java.io.IOException;
import java.text.Format;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
/**
* Timer是一種執行緒設施,用於安排以後在後臺執行緒中執行的任務。可安排任務執行一次,或者定期重複執行。
* Timer學習比較簡單,按照API把Timer類中的方法弄懂就夠用了。
*
* 此類是執行緒安全的:多個執行緒可以共享單個 Timer 物件而無需進行外部同步。
* 這一點很重要(即使是使用scheduleAtFixedRate方法的時候碰見延遲問題,也不會出現執行緒同步的問題)
*
* schedule()方法有四種引數形式:
*
* (1)、void schedule(TimerTask task, Date time) 安排在指定時間執行指定任務(如果傳遞的引數時間已過,則立即執行任務)
*
* (2)、void schedule(TimerTask task, long delay) 安排在指定延遲後執行指定任務
*
* (3)、void schedule(TimerTask task, Date firstTime, long period) 安排指定的任務在指定的時間開始進行重複的固定延遲執行。
* 在固定延遲執行中,根據前一次執行的實際執行時間來安排每次執行。如果由於任何原因(如垃圾回收或其他後臺活動)而延遲了某次執行,
* 則後續執行也將被延遲。從長期來看,執行的週期一般要略大於指定的週期。
*
* (4)、schedule(TimerTask task, long delay, long period) 安排指定的任務在指定延遲後開始進行重複的固定延遲執行。
* <span style="white-space: pre;"> </span>在固定延遲執行中,根據前一次執行的實際執行時間來安排每次執行。如果由於任何原因(如垃圾回收或其他後臺活動)而延遲了某次執行,
* 則後續執行也將被延遲。從長期來看,執行的週期一般要略大於指定的週期。
*
* scheduleAtFixedRate()方法有兩種引數形式
* 在固定速率執行中,相對於已安排的初始執行時間來安排每次執行。如果由於任何原因(如垃圾回收或其他背景活動)而延遲了某次執行,
* 則將快速連續地出現兩次或更多次執行,從而使後續執行能夠趕上來。從長遠來看,執行的頻率將正好是指定週期的倒數
*
* (1)、 void scheduleAtFixedRate(TimerTask task, Date firstTime, long period) 安排指定的任務在指定的時間開始進行重複的"固定速率"執行。
*
* (2)、void scheduleAtFixedRate(TimerTask task, long delay, long period) 安排指定的任務在指定的延遲後開始進行重複的"固定速率"執行。
*
* cancel() 方法:終止此計時器,丟棄所有當前已安排的任務。這不會干擾當前正在執行的任務(就是說已經進入run()方法的了就繼續執行,如果還有其他排隊的,那不執行)。
* <span style="white-space: pre;"> </span> 一旦終止了計時器,那麼它的執行執行緒也會終止,並且無法根據它安排更多的任務。
*
* int purge() 從此計時器的任務佇列中移除所有已取消的任務,如果沒有對這些任務的外部引用,則它們就成為垃圾回收的合格物件。 以時間換取了空間。 一般程式不必要用。
* 返回值是從佇列中移除的任務數。
*
*/
public class TimerTest {
public static void main(String[] args) throws ParseException {
final Timer timer = new Timer();
timer.schedule(new TimerTask(){
@Override
public void run() {
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date1=new Date();
String t1=df.format(date1);//取到格式化後的當前時間
String t2="2013-12-17 21:00:00";
Date date2 = null;
try {
date2 = df.parse(t2);//將字串轉換成時間格式
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(date1.getTime());
//指定定時器結束的條件,要不然會該定時器會一直執行下去
if(date1.getTime()>=date2.getTime()){
System.out.println(t1+"定時器停止了");
timer.cancel();//終止該定時器
}
}
}, 1000,2000);// 在1秒後執行此任務,每次間隔2秒
}
}
基礎的用法解釋都在程式碼的註釋當中。我們著重要說的是schedure 與 schedureAtFixeRate這兩個方法的區別以及schedureAtFixeRate方法是否存在同步問題 :
schedure (TimeTask task, Date t1, long period ) 方法在執行任務的時候如果某一任務執行過程中發生延遲,那麼下面的任務時間都會順延,也就是說,下一任務的啟動是根據前一任務執行結束的時間 + 指定的間隔週期。
schedureAtFixeRate(TimeTask task, Date t1, long period ) 方法中一個任務的啟動時間是根據前一任務的開始時間+指定的間隔週期。如果某一任務執行過程中發生延遲,那他後面的任務會迅速挨個執行,直到任務間隔週期正常。
注意後面的任務是迅速挨個執行的,而不是一起執行。
看個程式碼例項:
[java] view plaincopyprint?- import java.util.Date;
- import java.util.Timer;
- import java.util.TimerTask;
- /**
- * 演示scheduleAtFixedRate與schedule的區別
- * 證明scheduleAtFixedRate方法即使發生延遲的時候也是執行緒安全的。
- * @author HaiCheng
- */
- publicclass TimerTest2 {
- publicstaticvoid main(String[] args) {
- final Timer t1= new Timer();
- t1.schedule(new TimerTask() {
- int count=0;
- long flag=0;//時間標記
- @Override
- publicvoid run() {
- if(count!=0){
- System.out.println("間隔時間---->"+(new Date().getTime()-flag)+"----count的值---->"+count);
- }
- flag=new Date().getTime();//上面那行先執行,下面這行後執行的 時間會略有偏差 ,差不多2毫秒左右
- count++;
- if(count==3){
- try {
- Thread.sleep(2000);
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- if(count==25){
- t1.cancel();
- }
- }
- }, 0, 100);
- }
- }
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
/**
* 演示scheduleAtFixedRate與schedule的區別
* 證明scheduleAtFixedRate方法即使發生延遲的時候也是執行緒安全的。
* @author HaiCheng
*/
public class TimerTest2 {
public static void main(String[] args) {
final Timer t1= new Timer();
t1.schedule(new TimerTask() {
int count=0;
long flag=0;//時間標記
@Override
public void run() {
if(count!=0){
System.out.println("間隔時間---->"+(new Date().getTime()-flag)+"----count的值---->"+count);
}
flag=new Date().getTime();//上面那行先執行,下面這行後執行的 時間會略有偏差 ,差不多2毫秒左右
count++;
if(count==3){
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(count==25){
t1.cancel();
}
}
}, 0, 100);
}
}
執行結果: [java] view plaincopyprint?
- 間隔時間---->100----count的值---->1
- 間隔時間---->100----count的值---->2
- 間隔時間---->2000----count的值---->3
- 間隔時間---->100----count的值---->4
- 間隔時間---->100----count的值---->5
- 間隔時間---->100----count的值---->6
- 間隔時間---->100----count的值---->7
- 間隔時間---->100----count的值---->8
- 間隔時間---->100----count的值---->9
- 間隔時間---->100----count的值---->10
- 間隔時間---->100----count的值---->11
- 間隔時間---->100----count的值---->12
- 間隔時間---->100----count的值---->13
- 間隔時間---->100----count的值---->14
- 間隔時間---->100----count的值---->15
- 間隔時間---->100----count的值---->16
- 間隔時間---->100----count的值---->17
- 間隔時間---->100----count的值---->18
- 間隔時間---->101----count的值---->19
- 間隔時間---->100----count的值---->20
- 間隔時間---->100----count的值---->21
- 間隔時間---->100----count的值---->22
- 間隔時間---->100----count的值---->23
- 間隔時間---->100----count的值---->24
間隔時間---->100----count的值---->1
間隔時間---->100----count的值---->2
間隔時間---->2000----count的值---->3
間隔時間---->100----count的值---->4
間隔時間---->100----count的值---->5
間隔時間---->100----count的值---->6
間隔時間---->100----count的值---->7
間隔時間---->100----count的值---->8
間隔時間---->100----count的值---->9
間隔時間---->100----count的值---->10
間隔時間---->100----count的值---->11
間隔時間---->100----count的值---->12
間隔時間---->100----count的值---->13
間隔時間---->100----count的值---->14
間隔時間---->100----count的值---->15
間隔時間---->100----count的值---->16
間隔時間---->100----count的值---->17
間隔時間---->100----count的值---->18
間隔時間---->101----count的值---->19
間隔時間---->100----count的值---->20
間隔時間---->100----count的值---->21
間隔時間---->100----count的值---->22
間隔時間---->100----count的值---->23
間隔時間---->100----count的值---->24
將上面例子的schedule方法換成scheduleAtFixedRate 執行結果變為:
[java]
view plaincopyprint?
- 間隔時間---->100----count的值---->1
- 間隔時間---->100----count的值---->2
- 間隔時間---->2000----count的值---->3
- 間隔時間---->0----count的值---->4
- 間隔時間---->0----count的值---->5
- 間隔時間---->0----count的值---->6
- 間隔時間---->0----count的值---->7
- 間隔時間---->0----count的值---->8
- 間隔時間---->0----count的值---->9
- 間隔時間---->0----count的值---->10
- 間隔時間---->0----count的值---->11
- 間隔時間---->0----count的值---->12
- 間隔時間---->0----count的值---->13
- 間隔時間---->0----count的值---->14
- 間隔時間---->0----count的值---->15
- 間隔時間---->0----count的值---->16
- 間隔時間---->0----count的值---->17
- 間隔時間---->0----count的值---->18
- 間隔時間---->0----count的值---->19
- 間隔時間---->0----count的值---->20
- 間隔時間---->0----count的值---->21
- 間隔時間---->0----count的值---->22
- 間隔時間---->98----count的值---->23
- 間隔時間---->100----count的值---->24
間隔時間---->100----count的值---->1
間隔時間---->100----count的值---->2
間隔時間---->2000----count的值---->3
間隔時間---->0----count的值---->4
間隔時間---->0----count的值---->5
間隔時間---->0----count的值---->6
間隔時間---->0----count的值---->7
間隔時間---->0----count的值---->8
間隔時間---->0----count的值---->9
間隔時間---->0----count的值---->10
間隔時間---->0----count的值---->11
間隔時間---->0----count的值---->12
間隔時間---->0----count的值---->13
間隔時間---->0----count的值---->14
間隔時間---->0----count的值---->15
間隔時間---->0----count的值---->16
間隔時間---->0----count的值---->17
間隔時間---->0----count的值---->18
間隔時間---->0----count的值---->19
間隔時間---->0----count的值---->20
間隔時間---->0----count的值---->21
間隔時間---->0----count的值---->22
間隔時間---->98----count的值---->23
間隔時間---->100----count的值---->24
通過執行結果間隔時間的區別我們很容易區別開這兩個方法的使用。
通過count的值打印出的順序是對的,沒有重複的,說明scheduleAtFixedRate 方法的任務發生延遲的時候也不會出現執行緒安全問題。