先前的兩篇博文《任務調度(一)——jdk自帶的Timer》和《任務調度(二)——jdk自帶的Timer 動態改動任務運行計划》中,簡介了一下Timer,能夠實現幾本的功能。可是在多線程方面卻略顯不足。
依據Timer源代碼,能夠看到Timer是單線程的。
所以task都是串行運行。
假如當中一個task運行須要非常長的時間,那其它的task僅僅能干巴巴的等着。怎么辦!
如今就遇到了這種問題。
總不能由於這個小小的問題就去換別的任務調度框架吧,還是想用最簡單的方案去解決一下。所以ScheduledExecutorService就被我選中了。這個是怎么找到的?1.網上搜,2.好好的看Timer類的凝視:
翻譯一下:java5.0引入了java.util.concurrent包。當中java.util.concurrent.scheduledthreadpoolexecutor就是在並發有用工具當中之中的一個。scheduledthreadpoolexecutor是一個能夠反復運行任務的線程池,而且能夠指定任務的間隔和延遲時間。它作為比Timer/TimerTask更加通用的替代品。由於它同意多個服務線程,接受不同的時間單位,且不須要繼承TimeTask(只須要實現Runnable接口)。配置ScheduledThreadPoolExecutor為單線程,則與使用Timer等效。
ScheduledThreadPoolExecutor實現了ScheduledExecutorService接口。所以標題中使用了接口的名字。
ScheduledExecutorService提供了4個方法:
當中第二個方法比較特殊一點,第一個參數是Callable。別的都是Runnable,二者的差別不再這篇博文的討論范圍之內。就此略過。說一些其它三個方法。
schedule()方法第一個參數是任務實例,第二個參數是延遲時間,第三個是時間單元。
比方調用例如以下:
ScheduledExecutorService pool = Executors.newScheduledThreadPool(2); pool.schedule(task1, 5, TimeUnit.SECONDS);//延遲5s后,運行且僅僅運行一次task1
scheduleAtFixedRate()和scheduleWithFixedDelay方法參數是一樣的。
第一個參數是任務實例,第二個參數是延遲時間。第三個是間隔時間,第四個是時間單元。
這兩個方法的不同之處在方法名也能看得出來:scheduleAtFixedRate方法是依照固定頻率去運行任務的。而scheduleWithFixedDelay方法則是依照固定的延遲去運行任務。
/** * task1 * * @author arron * @date 2015年8月5日 下午2:08:34 * @version 1.0 */ public class Task1 implements Runnable{ @SuppressWarnings("deprecation") public void run() { System.out.println("----task1 start--------"+new Date().toLocaleString()); try { Thread.sleep(3000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("----3s later, task1 end--------"+new Date().toLocaleString()); } }測試scheduleAtFixedRate方法:
public static void main(String[] args) { ScheduledExecutorService pool = Executors.newScheduledThreadPool(1); Task1 t1 = new Task1(); //馬上運行t1,3s后任務結束,再等待2s(間隔時間-消耗時間),假設有空余線程時,再次運行該任務 pool.scheduleAtFixedRate(t1, 0, 5, TimeUnit.SECONDS); }運行結果如圖:

task1第二次運行的前提是,當前有空余的線程。
運行的開始時間則是上一次結束時間+(間隔時間-任務消耗的時間)。
增加這個差值小於0。即間隔時間小於任務消耗的時間,那就不會再等待,會馬上運行(當然得滿足前提)。
測試scheduleAtFixedRate方法:
public static void main(String[] args) { ScheduledExecutorService pool = Executors.newScheduledThreadPool(1); Task1 t1 = new Task1(); //馬上運行t1,3s后任務結束。再等待5s(間隔時間-消耗時間)。假設有空余線程時,再次運行該任務 pool.scheduleWithFixedDelay(t1, 0, 5, TimeUnit.SECONDS); }運行結果如圖:
就簡介到這里,下篇將會分享替換Timer的代碼。