執行緒執行者(十二)執行者控制被拒絕的任務
宣告:本文是《 Java 7 Concurrency Cookbook 》的第四章,作者: Javier Fernández González 譯者:許巧輝 校對:方騰飛,葉磊
執行者控制被拒絕的任務
當你想要結束執行者的執行,你使用shutdown()方法來表明它的結束。執行者等待正在執行或等待它的執行的任務的結束,然後結束它們的執行。
如果你在shutdown()方法和執行者結束之間,提交任務給執行者,這個任務將被拒絕,因為執行者不再接收新的任務。ThreadPoolExecutor類提供一種機制,在呼叫shutdown()後,不接受新的任務。
在這個指南中,你將學習如何通過實現RejectedExecutionHandler,在執行者中管理拒絕任務。
準備工作…
這個指南的例子使用Eclipse IDE實現。如果你使用Eclipse或其他IDE,如NetBeans,開啟它並建立一個新的Java專案。
如何做…
按以下步驟來實現的這個例子:
1.建立RejectedTaskController類,實現RejectedExecutionHandler介面。實現這個介面的rejectedExecution()方法。寫入被拒絕任務的名稱和執行者的名稱與狀態到控制檯。
public class RejectedTaskController implements RejectedExecutionHandler { @Override public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { System.out.printf("RejectedTaskController: The task %s has been rejected\n",r.toString()); System.out.printf("RejectedTaskController: %s\n",executor.toString()); System.out.printf("RejectedTaskController: Terminating:%s\n",executor.isTerminating()); System.out.printf("RejectedTaksController: Terminated:%s\n",executor.isTerminated()); }
2.實現Task類,實現Runnable介面。
public class Task implements Runnable{
3.宣告私有的、String型別的屬性name, 用來儲存任務的名稱。
private String name;
4.實現這個類的構造器,初始化這個類的屬性。
public Task(String name){ this.name=name; }
5.實現run()方法,寫入資訊到控制檯,表明這個方法開始執行。
@Override public void run() { System.out.println("Task "+name+": Starting");
6.等待一段隨機時間。
try { long duration=(long)(Math.random()*10); System.out.printf("Task %s: ReportGenerator: Generating a report during %d seconds\n",name,duration); TimeUnit.SECONDS.sleep(duration); } catch (InterruptedException e) { e.printStackTrace(); }
7.寫入資訊到控制檯,表明方法的結束。
System.out.printf("Task %s: Ending\n",name); }
8.重寫toString()方法,返回任務的名稱。
public String toString() { return name; }
9.實現這個示例的主類,通過建立Main類,並實現main()方法。
public class Main { public static void main(String[] args) {
10.建立一個RejectedTaskController物件,管理拒絕的任務。
RejectecTaskController controller=new RejectecTaskController();
11.使用Executors類的newCachedThreadPool()方法,建立ThreadPoolExecutor。
ThreadPoolExecutor executor=(ThreadPoolExecutor) Executors.newCachedThreadPool();
12.建立執行者的拒絕任務控制器。
executor.setRejectedExecutionHandler(controller);
13.建立任務並提交它們給執行者。
System.out.printf("Main: Starting.\n"); for (int i=0; i<3; i++) { Task task=new Task("Task"+i); executor.submit(task); }
14.使用shutdown()方法,關閉執行者。
System.out.printf("Main: Shutting down the Executor.\n"); executor.shutdown();
15.建立其他任務並提交給執行者。
System.out.printf("Main: Sending another Task.\n"); Task task=new Task("RejectedTask"); executor.submit(task);
16.寫入資訊到控制檯,表明程式結束。
System.out.println("Main: End"); System.out.printf("Main: End.\n");
這是如何工作的…
以下截圖顯示示例的執行結果:
你可以看出當執行者關閉時,任務被拒絕提交。RejectecTaskController將有關於任務和執行者的資訊寫入到控制檯。
為了管理執行者控制拒絕任務,你應該實現RejectedExecutionHandler介面。該介面有帶有兩個引數的方法rejectedExecution():
- Runnable物件,儲存被拒絕的任務
- Executor物件,儲存拒絕任務的執行者
每個被執行者拒絕的任務都會呼叫這個方法。你必須使用Executor類的setRejectedExecutionHandler()方法設定拒絕任務的處理器。
不止這些…
當執行者接收任務時,會檢查shutdown()是否已經被呼叫了。如果被呼叫了,它拒絕這個任務。首先,它查詢 setRejectedExecutionHandler()設定的處理器。如果有一個(處理器),它呼叫那個類的 rejectedExecution()方法,否則,它將拋RejectedExecutionExeption異常。這是一個執行時異常,所以你不需要 用catch語句來控制它。
參見
- 在第4章,執行緒執行者中的建立一個執行緒執行者指南