一、用java.util.Timer
使用JAVA類Timer可實現簡單的延遲和周期性任務,其中的任務使用java.util.TimerTask表示。任務的執行方式有兩種:
- 按固定速率執行:即scheduleAtFixedRate的兩個重載方法
Timer timer = new Timer(); timer. scheduleAtFixedRate(new TimerTask() { @Override public void run() { System.out.println("Timer is running"); } }, 2000, 5000);
- 按固定延遲執行:即schedule的4個重載方法
Timer timer = new Timer(); timer.schedule(new TimerTask() { @Override public void run() { System.out.println("Timer is running"); } }, 2000);
我們要實現一個定時任務,只需要實現TimerTask的run方法即可。每一個任務都有下一次執行時間nextExecutionTime(毫秒),如果是周期性的任務,那么每次執行都會更新這個時間為下一次的執行時間,當nextExecutionTime小於當前時間時,都會執行它。
Timer的缺陷
1、由於執行任務的線程只有一個,所以如果某個任務的執行時間過長,那么將破壞其他任務的定時精確性。如一個任務每1秒執行一次,而另一個任務執行一次需要5秒,那么如果是固定速率的任務,那么會在5秒這個任務執行完成后連續執行5次,而固定延遲的任務將丟失4次執行。
2、如果執行某個任務過程中拋出了異常,那么執行線程將會終止,導致Timer中的其他任務也不能再執行。
3、Timer使用的是絕對時間,即是某個時間點,所以它執行依賴系統的時間,如果系統時間修改了的話,將導致任務可能不會被執行。
二、使用ScheduledThreadPoolExecutor
由於Timer存在上面說的這些缺陷,在JDK1.5中,我們可以使用ScheduledThreadPoolExecutor來代替它,使用Executors.newScheduledThreadPool工廠方法或使用ScheduledThreadPoolExecutor的構造函數來創建定時任務,它是基於線程池的實現,不會存在Timer存在的上述問題,當線程數量為1時,它相當於Timer。
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5); scheduledThreadPool.schedule(new Runnable() { public void run() { System.out.println("delay 3 seconds"); } }, 3, TimeUnit.SECONDS); scheduledThreadPool.scheduleAtFixedRate(()-> System.out.println("delay 1 seconds, and excute every 3 seconds") , 1, 3, TimeUnit.SECONDS);