執行緒執行者(七)執行者延遲執行一個任務
宣告:本文是《 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。
注意事項:如果你想在給定時間執行一個任務,計算這個日期與當前日期的差異,使用這個差異作為任務的延遲。
以下截圖顯示這個示例執行的輸出:
你可以看出這些任務是如何開始執行的,一秒執行一個。所有任務都是同時提交給執行者的,但每個任務比之前的任務都有1秒的延遲。
不止這些…
你也可以使用Runnable介面實現任務,因為ScheduledThreadPoolExecutor類的schedule()方法接收這兩種型別(Runnable和Callable)的任務。
儘管ScheduledThreadPoolExecutor類是ThreadPoolExecutor類的子類,因此,它繼承 ThreadPoolExecutor類的所有功能,但Java建議使用ScheduledThreadPoolExecutor僅適用於排程任務。
最後,你可以配置ScheduledThreadPoolExecutor的行為,當你呼叫shutdown()方法時,並且有待處理的任務正在等待它們延遲結束。預設的行為是,不管執行者是否結束這些任務都將被執行。你可以使用ScheduledThreadPoolExecutor類的setExecuteExistingDelayedTasksAfterShutdownPolicy()方法來改變這種行為。使用false,呼叫 shutdown()時,待處理的任務不會被執行。
參見
- 在第4章,執行緒執行者中的執行者執行返回結果的任務指南