JavaSE實現任務調度的三種方式(十六)

勿以惡小而爲之,勿以善小而不爲--------------------------劉備

勸諸君,多行善事積福報,莫作惡

上一章簡單介紹了 JavaSE實現國際化操作(十五),如果沒有看過,請觀看上一章

一. 爲什麼要出現定時任務?

在實際生活和開發中,常常會遇到類似的情況, 如 1.女朋友生日那一天,發送定時消息,提醒生日快樂 2. 給某人寫郵件編寫好內容之後,在晚上10點時準時發送, 3 某天固定8點起牀,晚上10點睡覺 4.母親節,父親節時給父母發送消息。 等生活中的定時小例子 (鬧鐘,備忘錄都屬於定時)。

開發中,1. 給已經註冊的用戶,在用戶生日那天,發送生日祝福. 2. 公司員工,當入職滿一年時,增加年假至5天,入職5年時,增加年假至10天。 3.定時刪除三個月前的日誌記錄消息。 4. 定時監測網站訪問情況等開發中的定時小例子。

這些生活和開發實例,都屬於定時任務。 定時任務,是很常見的,也是很重要的。

JavaSE 階段提供了 三種方式,來實現定時任務。

JavaEE 階段,使用 Quartz 框架來實現定時任務。

二. JavaSE 階段實現定時任務

二.一 多線程 Runnable 和Thread 實現定時任務

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 
 * Thread 多線程通過休眠時間來實現定時執行
 * @author 兩個蝴蝶飛
 *
 */
public class ThreadDemo {
	public static void main(String []args){
		//定時的時間
		Long SLEEP_TIME=1000*5L;
		Runnable runnable=new Runnable() {
			@Override
			public void run() {
				while(true){
					try {
						//通過設置休眠,來達到定時的效果。 每5s執行一次 
						Thread.sleep(SLEEP_TIME);
						SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
						String localeDate=sdf.format(new Date());
						System.out.println("Thread 線程:當前時間爲:"+localeDate);
						
					} catch (InterruptedException e) {
						// TODO 自動生成的 catch 塊
						e.printStackTrace();
					}
				}
				
			}
		};
		
		Thread thread=new Thread(runnable);
		thread.start();
		
	}
}

控制檯打印輸出:

有圖片

如果想取消定時的話, 可以定義一個全局常量flag,flag默認是true, 將 while(true) 改成 while(flag), 當取消定時時,將flag 由true 改成false 即可。

二.二 TimerTask 和 Timer 實現定時任務

二.二.一 代碼編寫

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
/**
 * 
 * TimerTask 和Timer 實現定時任務
 * @author 兩個蝴蝶飛
 *
 */
public class TaskDemo {
	public static void main(String[] args) {
		Timer timer=new Timer();
		TimerTask task=new TimerTask() {	
			@Override
			public void run() {
				SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
				String localeDate=sdf.format(new Date());
				System.out.println("Task任務:當前時間爲:"+localeDate);
			}
		};
		timer.scheduleAtFixedRate(task,0,5000);
		
		//調用  cancel()方法來取消定時
		//timer.cancel();
	}
}

通過調用 Timer 對象的 scheduleAtFixedRate() 方法,來實現定時任務。

控制檯打印輸出:

有圖片

二.二.二 Timer中的調度方法

task 均爲執行定時任務的對象,時間單位爲 ms.

方法簽名 作用
schedule(TimerTask task, long delay) 在delay ms 後執行定時任務,只執行一次
schedule(TimerTask task, Date time) 在time 時間時執行定時任務,只執行一次
public void schedule(TimerTask task, long delay, long period) 在delay ms後執行定時任務,
並且每隔 period 毫秒再次執行任務,會多次執行,
以固定時間
schedule(TimerTask task, Date firstTime, long period) 在firstTime時間執行定時任務,
並且每隔 period毫秒再次執行任務,會多次執行,
以固定時間
scheduleAtFixedRate(TimerTask task, long delay, long period) 在delay ms後執行定時任務,
並且每隔 period 毫秒再次執行任務,會多次執行,
不一定均以固定時間執行
scheduleAtFixedRate(TimerTask task, Date firstTime, long period) 在firstTime時間執行定時任務,
並且每隔 period毫秒再次執行任務,會多次執行,
不一定均以固定時間執行

schedule()方法和 scheduleAtFixedRate()方法,是有一些區別的。

schedule()方法,假設是每5s執行一次,由5s,10s,15s,20s時執行, 但由於CPU徵用導致定時任務並沒有在5s這個時間上執行,而是在9s時執行了,延遲了4s,那麼下一次該任務執行的時間是 9+5=14s,而不是原計劃的10s. 這樣會導致可能漏掉調度的情況。

scheduleAtFixedRate()方法,假設是每5s執行一次,由5s,10s,15s,20s時執行, 但由於CPU徵用導致定時任務並沒有在5s這個時間上執行,而是在9s時執行了,延遲了4s,那麼下一次該任務執行的時間還是10s, 與原計劃一樣(會將間隔時間的period=5000 變成period=1000,但下下一次仍然是5000), 不會導致漏掉調度的情況。

故常常使用的是 scheduleAtFixedRate() 方法。

二.三 ScheduledExecutor 實現定時任務

在 java.util.concurrent 包下

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
 * ScheduledExecutor 實現定時調度
 * @author 兩個蝴蝶飛
 *
 */
public class ScheduleDemo {
	public static void main(String[] args) {
		//定義定時任務
		Runnable runnable=new Runnable() {
			@Override
			public void run() {
				SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
				String localeDate=sdf.format(new Date());
				System.out.println("Scheduled調度:當前時間爲:"+localeDate);
			}
		};
		//定義調度服務
		ScheduledExecutorService scheduledExecutorService=Executors.newSingleThreadScheduledExecutor();
		//運行, 哪個任務,開始時間,間隔時間,間隔單位
		scheduledExecutorService.scheduleAtFixedRate(runnable, 0, 2, TimeUnit.SECONDS);
	}
}

控制檯打印輸出:

有圖片

三. JavaSE 實現調度的不足

上面的三種方式,雖然都實現了定時任務,但面對複雜多變的定時任務情況,就顯得力不從心了。

如,

  1. 無法實現類似 ‘每年的母親節給母親發送祝福’,‘每個月的最後一天顯示員工的本月的工作情況’,‘距離每個月10號最近的工作日發薪資’ 等非固定日期的情況。開發者不能在程序中進行判斷日期。

  2. 無法與當前主流框架 Spring 進行很好的整合。

  3. 定時任務的事務處理,需要開發者自己進行處理。

  4. 定時任務持久化保存

想處理好定時任務,可以學習一下 Quartz 定時任務框架。


謝謝您的觀看!!!
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章