ScheduledExecutorService的scheduleAtFixedRate和scheduleWithFixedDelay方法的區別

ScheduledExecutorService是java.util.concurrent併發包下的一個接口,表示調度服務~,它定義了以下幾個方法:

 

public ScheduledFuture<?> schedule(Runnable command, 
									long delay, TimeUnit unit);
 
 public <V> ScheduledFuture<V> schedule(Callable<V> callable,
                                           long delay, TimeUnit unit);
 
 public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
                                                  long initialDelay,
                                                  long period,
                                                  TimeUnit unit);
												 
 public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
                                                     long initialDelay,
                                                     long delay,
                                                     TimeUnit unit); 

 

前2個的任務是指定在延遲時間後執行一次任務,後2個方法則表示每間隔一段時間定時執行任務。

ScheduledExecutorService的後兩個方法比較容易搞混,下面就用小例子來搞清楚:

 

public class DiffTest {
	
	private static ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
	
	public static void main(String[] args) {
		final long executeTime = (long) (Math.random()*10);
		
		
		//scheduleAtFixedRate
		executor.scheduleAtFixedRate(new Runnable(){
			//模擬耗時任務,耗時是10s以內的任意數
			@Override
			public void run() {
				try {
					SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
					System.out.print(sdf.format(new Date()) + " 開始執行, ");
					Thread.sleep(3000);//3s
					System.out.println(sdf.format(new Date()) + "結束執行 ================");
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			
		}, 0, 5, TimeUnit.SECONDS);//每隔5s
		
		
	}
	
}

 當間隔時間(5s)大於任務的執行時間(3s),運行結果爲:

 

12:00:03 開始執行, 12:00:06結束執行 ================

12:00:08 開始執行, 12:00:11結束執行 ================

12:00:13 開始執行, 12:00:16結束執行 ================

12:00:18 開始執行, 12:00:21結束執行 ================

12:00:23 開始執行, 12:00:26結束執行 ================

12:00:28 開始執行, 12:00:31結束執行 ================

 

當間隔時間(5s)小於程序(7s)執行時間(將耗時改爲7s, 每隔5s的設置就會失效)

12:01:26 開始執行, 12:01:33結束執行 ================

12:01:33 開始執行, 12:01:40結束執行 ================

12:01:40 開始執行, 12:01:47結束執行 ================

12:01:47 開始執行, 12:01:54結束執行 ================

12:01:54 開始執行, 12:02:01結束執行 ================

12:02:01 開始執行, 12:02:08結束執行 ================

說明:scheduleAtFixedRate是以上一次任務的開始時間爲間隔的,並且當任務執行時間大於設置的間隔時間時,真正間隔的時間由任務執行時間爲準!

 

再來測試下scheduleWithFixedDelay:

executor.scheduleWithFixedDelay(new Runnable(){
			//模擬耗時任務,耗時是10s以內的任意數
			@Override
			public void run() {
				try {
					SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
					System.out.print(sdf.format(new Date()) + " 開始執行, ");
					Thread.sleep(3000);//3s
					System.out.println(sdf.format(new Date()) + "結束執行 ================");
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			
		}, 0, 5, TimeUnit.SECONDS);//每隔5s

  當間隔時間(5s)大於任務的執行時間(3s),運行結果爲:

12:46:54 開始執行, 12:46:57結束執行 ================

12:47:02 開始執行, 12:47:05結束執行 ================

12:47:10 開始執行, 12:47:13結束執行 ================

12:47:18 開始執行, 12:47:21結束執行 ================

12:47:26 開始執行, 12:47:29結束執行 ================

 

12:47:34 開始執行, 12:47:37結束執行 ================

 

當間隔時間(5s)小於程序(7s)執行時間,此時運行結果爲:

12:48:12 開始執行, 12:48:19結束執行 ================

12:48:24 開始執行, 12:48:31結束執行 ================

12:48:36 開始執行, 12:48:43結束執行 ================

12:48:48 開始執行, 12:48:55結束執行 ================

12:49:00 開始執行, 12:49:07結束執行 ================

12:49:12 開始執行, 12:49:19結束執行 ================

說明:scheduleWithFixedDelay是以上一次任務的結束時間爲間隔的!

 

順便說下,當定時調度遇到異常時,是否會影響下次任務的執行:

public class DiffTest {
	
	private static ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
	
	private static int  a;
	
	private static int[] aa = {1,2,3};
	
	public static void main(String[] args) {
		
		//scheduleAtFixedRate
		executor.scheduleWithFixedDelay(new Runnable(){
			//模擬耗時任務,耗時是10s以內的任意數
			@Override
			public void run() {
				try {
					SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
					System.out.println(sdf.format(new Date()) + " 開始執行");
					System.out.println("執行結果:" + aa[a++]);
					System.out.println("==============");
					
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
			
		}, 0, 5, TimeUnit.SECONDS);//每隔5s
	}
}

 運行之,結果爲:

19:13:07 開始執行

執行結果:1

==============

19:13:12 開始執行

執行結果:2

==============

19:13:17 開始執行

執行結果:3

==============

19:13:22 開始執行

java.lang.ArrayIndexOutOfBoundsException: 3

at com.nineclient.echat.plugin.DiffTest$1.run(DiffTest.java:28)

at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)

at java.util.concurrent.FutureTask$Sync.innerRunAndReset(FutureTask.java:351)

at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:178)

at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:178)

at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)

at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)

at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)

at java.lang.Thread.run(Thread.java:722)

19:13:27 開始執行

java.lang.ArrayIndexOutOfBoundsException: 4

at com.nineclient.echat.plugin.DiffTest$1.run(DiffTest.java:28)

at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)

at java.util.concurrent.FutureTask$Sync.innerRunAndReset(FutureTask.java:351)

at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:178)

at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:178)

at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)

at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)

at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)

at java.lang.Thread.run(Thread.java:722)

這說明,雖然執行到第4次時發生了異常,但並不影響下一次的執行。但如果你沒有異常捕獲機制,則會影響,比如改成:

executor.scheduleWithFixedDelay(new Runnable(){
			//模擬耗時任務,耗時是10s以內的任意數
			@Override
			public void run() {
				SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
				System.out.println(sdf.format(new Date()) + " 開始執行");
				System.out.println("執行結果:" + aa[a++]);
				System.out.println("==============");
			}
			
		}, 0, 5, TimeUnit.SECONDS);//每隔5s

 運行結果爲:

19:14:39 開始執行

執行結果:1

==============

19:14:44 開始執行

執行結果:2

==============

19:14:49 開始執行

執行結果:3

==============

19:14:54 開始執行

 

 

之後就不再運行了。。所以務必在被調度的任務上加上異常捕獲!

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