Java併發基礎02:傳統執行緒技術中的定時器技術

公眾號_程式設計師私房菜發表於2019-01-07

歡迎關注我的微信公眾號:程式設計師私房菜(id:eson_15)

傳統執行緒技術中有個定時器,定時器的類是Timer,我們使用定時器的目的就是給它安排任務,讓它在指定的時間完成任務。所以先來看一下Timer類中的方法(主要看常用的TimerTask()方法):

返回值 方法名 方法描述
void schedule(TimerTask task, long delay) 安排在指定延遲後執行指定的任務。
void schedule(TimerTask task, long delay, long period) 安排指定的任務從指定的延遲後開始進行重複的固定延遲執行。
void schedule(TimerTask task, Date time) 安排在指定的時間執行指定的任務
void schedule(TimerTask task, Date firstTime, long period) 安排指定的任務在指定的時間開始進行重複的固定延遲執行。

前面兩個是在指定延遲後執行或者重複執行,後面兩個是在指定時間執行或者重複執行。我們以前兩個為例來研究一下定時器的使用。

先寫一個簡單的使用定時器的demo,然後慢慢引申。

public class TraditionalTimer {

	public static void main(String[] args) {
		//簡單定時器的demo
		new Timer().schedule(new TimerTask() {			
			@Override
			public void run() {
				//實際中會扔一個物件進來,我們就可以在這裡操作這個物件的所有方法了
				System.out.println("--boom--");//爆炸
			}
		}, 2000,3000); 

		//列印秒鐘,一秒輸出一次,用來方便觀察的
		while(true) {
			System.out.println(new Date().getSeconds());
			try {
				Thread.sleep(1000);
			} catch(Exception e) {
				e.printStackTrace();
			}
		}
	}
}
複製程式碼

我們用匿名內部類來定義了一個TimerTask物件,需要重寫run()方法,然後執行這個程式,可以看出來第一次2秒鐘後列印“--boom--,後面每隔3秒列印一次。

我們也可以自己來實現上面這個重複執行,我們用定時器的“連環套”!也就是定時器中再套定時器,一個定時器任務執行完了,在任務的最後再裝一個定時器。那麼我們需要先定義一個自己的定時器任務,在自己的定時器任務中再裝一個定時器,把自定義的定時器任務扔進去。然後我們開啟定時器的時候把自己定義的定時器任務扔進去即可。如下:

public class TraditionalTimer {

	public static void main(String[] args) {
		
		//自定義一個定時器任務
		class MyTimerTask extends TimerTask {			
			@Override
			public void run() {
				System.out.println("--boom--");
				//任務執行完再裝一個定時器,扔進自定義的定時器任務
				new Timer().schedule(new MyTimerTask(), 3000);
			}
		}
		new Timer().schedule(new MyTimerTask(), 2000);//外面開啟定時器
		
		while(true) {//列印秒鐘,一秒輸出一次
			System.out.println(new Date().getSeconds());
			try {
				Thread.sleep(1000);
			} catch(Exception e) {
				e.printStackTrace();
			}
		}
	}
}
複製程式碼

這樣的話,我們通過定時器的“連環套”很輕鬆的實現了連環爆炸。但是現在問題來了,上面提供的方法中重複執行都是每隔固定的時間,如果我想要隔2秒執行一次,再隔4秒執行一次,再隔2秒執行一次,再隔4秒執行一次……這該如何實現呢?

可以這樣,我們定義一個全域性的私有成員變數來記錄爆炸次數,奇數的時候隔2秒炸,偶數的次數的話隔4秒炸,或者反過來也行,修改如下:

public class TraditionalTimer {

	private static int count = 0; //記錄爆炸的次數
	public static void main(String[] args) {	

		class MyTimerTask extends TimerTask {			
			@Override
			public void run() {
				count = (count + 1) % 2; //結果只有0和1
				System.out.println("--boom--");
				new Timer().schedule(new MyTimerTask(), 2000+2000*count);//根據count結果設定新的定時時間
			}
		}
		new Timer().schedule(new MyTimerTask(), 2000);
		
		while(true) {//列印秒鐘,一秒輸出一次
			System.out.println(new Date().getSeconds());
			try {
				Thread.sleep(1000);
			} catch(Exception e) {
				e.printStackTrace();
			}
		}
	}
}
複製程式碼

這樣的話,我們就實現了自定義爆炸間隔了。上面這個是通過定義一個全域性私有變數來實現,其實我們也可以這麼幹:不是要實現兩個不同時間間隔的連環炸麼?我可以定義兩個定時器任務A和B,在A執行完開啟定時器,把B任務裝進去,B執行完開啟定時器把A裝進去,這樣也可以。如下:

public class TraditionalTimer {

	public static void main(String[] args) {
		
		new Timer().schedule(new MyTimerTaskA(), 2000);//A和B隨便開一個
		
		while(true) {//列印秒鐘,一秒輸出一次
			System.out.println(new Date().getSeconds());
			try {
				Thread.sleep(1000);
			} catch(Exception e) {
				e.printStackTrace();
			}
		}
	}

}
//自定義兩個定時器任務類,繼承TimerTask即可
class MyTimerTaskA extends TimerTask {

	@Override
	public void run() {
		System.out.println("--boomA--");
		new Timer().schedule(new MyTimerTaskB(), 4000);
	}			
}
class MyTimerTaskB extends TimerTask {

	@Override
	public void run() {
		System.out.println("--boomB--");
		new Timer().schedule(new MyTimerTaskA(), 2000);
	}	
}
複製程式碼

這樣就可以實現自定義時間間隔的連環炸了。傳統的定時器技術就總結這麼多吧~如果有問題,歡迎指正,我們一同進步!

也歡迎大家關注我的微信公眾號:程式設計師私房菜。我會持續輸出更多文章。

公眾號

相關文章