HOWTO · Java
Java 排程
本文介紹如何在 Java 中排程任務。
排程是以固定的時間間隔執行任務或功能的過程。排程在執行批處理、傳送基於事件的觸發器(如生日祝福)、傳送推送通知中找到了它的用途。這些過程必須根據給定的條件和時間間隔在明確定義的時間執行。
使用 Java 中的 ScheduledExecutorService 介面方法排程程序
package scheduling;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
public class ScheduleTask {
private static int counter = 0;
public static void main(String[] args) throws InterruptedException {
ScheduledExecutorService service = Executors.newScheduledThreadPool(1);
Runnable executeTask = () -> {
counter++;
System.out.println("Task" + counter);
};
ScheduledFuture<?> scheduleAtFixedRate =
service.scheduleAtFixedRate(executeTask, 5, 1, TimeUnit.SECONDS);
while (true) {
Thread.sleep(1000);
if (counter == 5) {
System.out.println("Stopping the scheduled task!");
scheduleAtFixedRate.cancel(true);
service.shutdown();
break;
}
}
}
}
在上面的程式碼中,首先,一個靜態計數器變數被初始化為零值。newScheduledThreadPool 是 Executors 類的靜態方法。該方法建立一個執行緒池,該執行緒池應該使用引數列表中給出的引數定期執行。所以在我們的例子中,建立了一個執行緒來執行,因為方法引數列表中的引數定義了執行緒池的數量。該方法返回一個 ScheduledExecutorService 例項,該例項儲存在 service 引用變數中,如果池大小小於零,則丟擲 IllegalArgumentException。
Runnable 是一個任何類都可以擴充套件的介面,並且是功能性介面。它只有一個靜態方法作為 run 方法,供執行緒執行。使用表示為符號 ()-> 括號和箭頭的 lambda 表示式,該結構表明我們沒有將任何引數傳遞給 run 方法。我們已經在 run 方法的定義中定義了語句。塊內的語句將增加計數器變數並在控制檯輸出中列印任務。這些所有語句都由名為 executeTask 變數的變數引用。
service 引用變數呼叫 ScheduledExecutorService 介面的 scheduleAtFixedRate 方法。該方法建立並執行應該在初始延遲之後和給定時間段內稍後執行的週期性任務。它需要四個引數,一個應該執行的 runnable 命令,initialDelay 變數是延遲第一次執行的時間,period 表示連續執行之間的持續時間,而 unit 是時間單位,以秒為單位、分鐘和小時。一旦方法被呼叫,執行緒就開始執行。
在 while 迴圈中,首先強制當前執行的執行緒休眠。Thread.sleep() 方法在定義的時間內暫時停止當前正在執行的執行緒。該引數是當前工作執行緒應該停止的毫秒數。如果值為負,則該方法丟擲 IllegalArgumentException,如果當前執行緒被中斷,則丟擲 InterruptedException。稍後使用定義的值檢查計數器的值。此檢查用於執行 while 方法一定次數。否則,該塊將執行一個永遠不會終止的無限數。在 while 塊中,scheduleAtFixedRate 變數呼叫 cancel 方法,該方法取消執行緒的當前執行。該函式還接受一個布林引數,指示當前正在執行的執行緒是否可以中斷。
service.shutdown 方法啟動關閉過程,在該過程中應該執行先前提交的任務,並且不接受任何新任務。
上述程式碼塊的輸出如下。
Task1
Task2
Task3
Task4
Task5
Stopping the scheduled task!
使用 Java 中的 Timer 類排程執行緒
下面是使用其建構函式例項化兩個使用者定義的類物件的簡單程式碼塊。TimerImplementation 是使用者定義的類。建立了一個 Timer 例項,它將建立一個新執行緒。然後新建立的計時器物件將呼叫 scheduleAtFixedRate 方法。該方法將引數作為需要排程的任務,延遲以毫秒為單位延遲任務,而週期是以毫秒為單位連續執行的時間。
package timer;
import java.util.Timer;
public class UsingTimerClass {
public static void main(String[] args) {
TimerImplementation timer1 = new TimerImplementation("Thread1");
TimerImplementation timer2 = new TimerImplementation("Thread2");
Timer t = new Timer();
t.scheduleAtFixedRate(timer1, 0, 2000);
t.scheduleAtFixedRate(timer2, 0, 1000);
}
}
下面是使用者定義類的實現。TimerImplementation 類擴充套件了 TimerTask 抽象類,該抽象類包含一個名為 run 的抽象方法。我們在使用者定義的類中擴充套件 TimerTask 類,然後覆蓋 run 方法。
該類具有一個使用者定義的建構函式,用於將使用者定義的名稱設定為執行緒物件。
我們可以線上程 run 方法中給出實際的邏輯。它包括一個作為 print 的語句,它將列印當前正在執行的執行緒的名稱。Thread.currentThread().getName() 返回當前執行執行緒的名稱。sleep 方法通過 Thread1 呼叫,中斷執行 1000 毫秒。如果任何執行緒中斷當前執行緒,sleep 方法會丟擲 InterruptedException,這就是它被包含在 try-catch 塊中的原因。
package timer;
import java.util.TimerTask;
public class TimerImplementation extends TimerTask {
private String name;
public TimerImplementation(String n) {
this.name = n;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " " + name);
if ("Thread1".equalsIgnoreCase(name)) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
以下是上述程式碼的永無止境的輸出。由於我們沒有在 run 方法中定義任何終止條件,執行緒將無休止地執行,直到應用外部停止來終止主執行緒的執行。
Timer-0 Thread1
Timer-0 Thread2
Timer-0 Thread2
Timer-0 Thread2
Timer-0 Thread1
Timer-0 Thread2
Timer-0 Thread2
Timer-0 Thread1
Timer-0 Thread2