1. 程式人生 > >執行緒執行者(七)執行者延遲執行一個任務

執行緒執行者(七)執行者延遲執行一個任務

宣告:本文是《 Java 7 Concurrency Cookbook 》的第四章,作者: Javier Fernández González     譯者:許巧輝     校對:方騰飛,葉磊

執行者延遲執行一個任務

執行者框架提供ThreadPoolExecutor類,使用池中的執行緒來執行Callable和Runnable任務,這樣可以避免所有執行緒的建立操作。當你提交一個任務給執行者,會根據執行者的配置儘快執行它。在有些使用情況下,當你對儘快執行任務不感覺興趣。你可能想要在一段時間之後執行任務或週期性地執行任務。基於這些目的,執行者框架提供 ScheduledThreadPoolExecutor類。

在這個指南中,你將學習如何建立ScheduledThreadPoolExecutor和如何使用它安排任務在指定的時間後執行。

準備工作…

這個指南的例子使用Eclipse IDE實現。如果你使用Eclipse或其他IDE,如NetBeans,開啟它並建立一個新的Java專案。

如何做…

按以下步驟來實現的這個例子:

1.建立Task類,實現Callable介面,引數化為String型別。

public class Task implements Callable<String> {

2.宣告一個私有的、型別為String、名為name的屬性,用來儲存任務的名稱。

private String name;

3.實現Task類的構造器,初始化name屬性。

public Task(String name) {
this.name=name;
}

4.實現call()方法,寫入實際日期到控制檯,返回一個文字,如:Hello, world。

public String call() throws Exception {
System.out.printf("%s: Starting at : %s\n",name,new Date());
return "Hello, world";
}

5.實現示例的主類,建立Main類,實現main()方法。

public class Main {
public static void main(String[] args) {

6.使用Executors類的newScheduledThreadPool()方法,建立ScheduledThreadPoolExecutor類的一個執行者。傳入引數1。

ScheduledThreadPoolExecutor executor=(ScheduledThreadPoolExecutor)Executors.newScheduledThreadPool(1);

7.使用ScheduledThreadPoolExecutor例項的schedule()方法,初始化和開始一些任務(本例中5個任務)。

System.out.printf("Main: Starting at: %s\n",new Date());
for (int i=0; i<5; i++) {
Task task=new Task("Task "+i);
executor.schedule(task,i+1 , TimeUnit.SECONDS);
}

8.使用shutdown()方法關閉執行者。

executor.shutdown();

9.使用執行者的awaitTermination()方法,等待所有任務完成。

try {
executor.awaitTermination(1, TimeUnit.DAYS);
} catch (InterruptedException e) {
e.printStackTrace();
}

10.寫入一條資訊表明程式結束時間。

System.out.printf("Main: Ends at: %s\n",new Date());

它是如何工作的…

在這個示例中,關鍵的一點是Main類和ScheduledThreadPoolExecutor的管理。正如使用ThreadPoolExecutor類建立預定的執行者,Java建議利用Executors類。在本例中,你使用newScheduledThreadPool()方法。你用1作為引數傳給這個方法。這個引數是你想要讓執行緒池建立的執行緒數。

你必須使用schedule()方法,讓執行者在一段時間後執行任務。這個方法接收3個引數,如下:

  • 你想要執行的任務
  • 你想要讓任務在執行前等待多長時間
  • 時間單位,指定為TimeUnit類的常數

在本例中,每個任務等待的秒數(TimeUnit.SECONDS)等於它在任務陣列中的位置再加1。

注意事項:如果你想在給定時間執行一個任務,計算這個日期與當前日期的差異,使用這個差異作為任務的延遲。

以下截圖顯示這個示例執行的輸出:

5

你可以看出這些任務是如何開始執行的,一秒執行一個。所有任務都是同時提交給執行者的,但每個任務比之前的任務都有1秒的延遲。

不止這些…

你也可以使用Runnable介面實現任務,因為ScheduledThreadPoolExecutor類的schedule()方法接收這兩種型別(Runnable和Callable)的任務。

儘管ScheduledThreadPoolExecutor類是ThreadPoolExecutor類的子類,因此,它繼承 ThreadPoolExecutor類的所有功能,但Java建議使用ScheduledThreadPoolExecutor僅適用於排程任務。

最後,你可以配置ScheduledThreadPoolExecutor的行為,當你呼叫shutdown()方法時,並且有待處理的任務正在等待它們延遲結束。預設的行為是,不管執行者是否結束這些任務都將被執行。你可以使用ScheduledThreadPoolExecutor類的setExecuteExistingDelayedTasksAfterShutdownPolicy()方法來改變這種行為。使用false,呼叫 shutdown()時,待處理的任務不會被執行。

參見

  • 在第4章,執行緒執行者中的執行者執行返回結果的任務指南