Java 的 ScheduledThreadPoolExecutor 可以很方便地實現簡單的定時任務,
其中有兩個方法:
- 定時速率任務: scheduleAtFixedRate(command, initialDelay, period, unit)
- 固定延遲任務:scheduleWithFixedDelay(command, initialDelay, period, unit)
這兩個方法很相似,但又有點不同,
這邊做一下說明及練習記錄。
scheduleAtFixedRate 是定時速率任務,它會盡可能地以一定的時間間隔執行任務,
邏輯是像這樣:
1. 當任務開始時,開始等待時間間隔設定的時間。
2. 等完時間間隔了以後,檢查上個任務執行完成了沒有,如果執行完成了就直接執行下個任務,如果還沒執行完,就繼續等待任務完成後再執行下個任務,開始執行下個任務時回到第1步。
scheduleWithFixedDelay 是固定延遲任務,它會在每一次任務完成後,等待設定的時間間隔,然後再執行下一次任務,
邏輯是像這樣:
1. 當任務完成後,開始等待時間間隔設定的時間。
2. 等完時間間隔了以後,直接執行下一個任務,等任務完成後回到第1步。
下面直接展示範例並印出執行過程,可以更好地理解這兩個 method 的特性。
package test;
import java.time.Instant;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class ScheduledTest {
public static void main(String[] args) {
ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(5);
//定時速率任務:
//ScheduledThreadPoolExecutor.scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)
//在 initialDelay 過後開始執行第一次工作,
//當開始執行工作時就會開始計算 period,如果 period 時間到了且上一個工作已做完了就會執行下一次工作,
//如果 period 時間到了但上一個工作還未做完,就會等到上一個工作作完後馬上執行下一次工作。
//此例為工作需花費3秒,period 設 1 秒,所以 period 時間到時上一個工作會還沒做完,
//所以會等待上一個工作做完好直接執行下一個工作。
scheduledThreadPoolExecutor.scheduleAtFixedRate(() -> {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ssxxx")
.withZone(ZoneId.of("+0000"));
System.out.println(dtf.format(Instant.now()) + " --> test AtFixedRate - Start");
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(dtf.format(Instant.now()) + " --> test AtFixedRate - End");
}, 0, 1, TimeUnit.SECONDS);
/** 2024-06-28 08:11:07+00:00 --> test AtFixedRate - Start
2024-06-28 08:11:10+00:00 --> test AtFixedRate - End
2024-06-28 08:11:10+00:00 --> test AtFixedRate - Start
2024-06-28 08:11:13+00:00 --> test AtFixedRate - End
2024-06-28 08:11:13+00:00 --> test AtFixedRate - Start
2024-06-28 08:11:16+00:00 --> test AtFixedRate - End
*/
//此例為工作需花費3秒,period 設 5 秒,所以 period 時間到後上一個工作已經做完,
//所以會直接執行下一個工作。
scheduledThreadPoolExecutor.scheduleAtFixedRate(() -> {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ssxxx")
.withZone(ZoneId.of("+0000"));
System.out.println(dtf.format(Instant.now()) + " --> test AtFixedRate - Start");
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(dtf.format(Instant.now()) + " --> test AtFixedRate - End");
}, 0, 5, TimeUnit.SECONDS);
/** 2024-06-28 08:12:30+00:00 --> test AtFixedRate - Start
2024-06-28 08:12:33+00:00 --> test AtFixedRate - End
2024-06-28 08:12:35+00:00 --> test AtFixedRate - Start
2024-06-28 08:12:38+00:00 --> test AtFixedRate - End
2024-06-28 08:12:40+00:00 --> test AtFixedRate - Start
2024-06-28 08:12:43+00:00 --> test AtFixedRate - End
*/
//固定延遲任務:
//ScheduledThreadPoolExecutor.scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit)
//在 initialDelay 過後開始執行第一次工作,
//工作執行完時才會就會開始計算 period,如果 period 時間到了就會執行下一次工作。
//此例為工作需花費3秒,period 設 1 秒,所以 period 時間到上一個工作會還沒做完,
//所以會等待上一個工作做完好直接執行下一個工作。
scheduledThreadPoolExecutor.scheduleWithFixedDelay(() -> {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ssxxx")
.withZone(ZoneId.of("+0000"));
System.out.println(dtf.format(Instant.now()) + " --> test WithFixedDelay - Start");
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(dtf.format(Instant.now()) + " --> test WithFixedDelay - End");
}, 0, 1, TimeUnit.SECONDS);
/** 2024-06-28 08:14:39+00:00 --> test WithFixedDelay - Start
2024-06-28 08:14:42+00:00 --> test WithFixedDelay - End
2024-06-28 08:14:43+00:00 --> test WithFixedDelay - Start
2024-06-28 08:14:46+00:00 --> test WithFixedDelay - End
2024-06-28 08:14:47+00:00 --> test WithFixedDelay - Start
2024-06-28 08:14:50+00:00 --> test WithFixedDelay - End
*/
//此例為工作需花費3秒,period 設 5 秒,待上一個工作結束後
//會等待 period 的時間(也就是5秒)後執行下一個工作。
scheduledThreadPoolExecutor.scheduleWithFixedDelay(() -> {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ssxxx")
.withZone(ZoneId.of("+0000"));
System.out.println(dtf.format(Instant.now()) + " --> test WithFixedDelay - Start" );
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(dtf.format(Instant.now()) + " --> test WithFixedDelay - End" );
}, 0, 5, TimeUnit.SECONDS);
/** 2024-06-28 08:20:43+00:00 --> test WithFixedDelay - Start
2024-06-28 08:20:46+00:00 --> test WithFixedDelay - End
2024-06-28 08:20:51+00:00 --> test WithFixedDelay - Start
2024-06-28 08:20:54+00:00 --> test WithFixedDelay - End
2024-06-28 08:20:59+00:00 --> test WithFixedDelay - Start
2024-06-28 08:21:02+00:00 --> test WithFixedDelay - End
*/
}
}
參考資料:
沒有留言 :
張貼留言