1. 程式人生 > >定製併發類(四)實現ThreadFactory介面生成自定義的執行緒

定製併發類(四)實現ThreadFactory介面生成自定義的執行緒

宣告:本文是《 Java 7 Concurrency Cookbook 》的第七章,作者: Javier Fernández González     譯者:許巧輝

實現ThreadFactory介面生成自定義的執行緒

在面向物件程式設計的世界中,工廠模式(factory pattern)是一個被廣泛使用的設計模式。它是一個建立模式,它的目的是開發一個類,這個類的使命是建立一個或多個類的物件。然後,當我們要建立一個類的一個物件時,我們使用這個工廠而不是使用new操作。

  • 使用這個工廠,我們集中物件的建立,獲取容易改變建立物件的類的優勢,或我們建立這些物件的方式,容易限制建立物件的有限資源。比如,我們只能有一個型別的N個物件,就很容易產生關於物件建立的統計資料。

Java提供ThreadFactory介面,用來實現一個Thread物件工廠。Java併發API的一些高階工具,如執行者框架(Executor framework)或Fork/Join框架(Fork/Join framework),使用執行緒工廠建立執行緒。

在Java併發API中的其他工廠模式的例子是Executors類。它提供許多方法來建立不同型別的Executor物件。

在這個指南中,你將繼承Thread類,以新增新功能,並且你將實現一個執行緒工廠來建立這個新類的執行緒。

準備工作…

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

如何做…

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

1.建立一個繼承Thread類的MyThread類。

 public class MyThread extends Thread {

 

2.宣告3個私有的、Date型別的屬性:creationDate、startDate和finishDate。

 private Date creationDate;
 private Date startDate;
 private Date finishDate;

 

3.實現這個類的構造器。它接收名稱和要執行的Runnable物件引數。儲存執行緒的建立日期。

 public MyThread(Runnable target, String name ){
 super(target,name);
 setCreationDate();
 }

 

4.實現run()方法。儲存執行緒的開始時間,呼叫父類的run()方法,儲存執行的結束時間。

 method of the parent class, and store the finish date of the execution.
 @Override
 public void run() {
 setStartDate();
 super.run();
 setFinishDate();
 }

 

5.實現一個方法用來設定creationDate屬性值。

 public void setCreationDate() {
 creationDate=new Date();
 }

 

6.實現一個方法用來設定startDate屬性值。

 public void setStartDate() {
 startDate=new Date();
 }

 

7.實現一個方法用來設定finishDate屬性值。

 public void setFinishDate() {
 finishDate=new Date();
 }

 

8.實現getExecutionTime()方法,用來計算執行緒的執行時間(結束日期與開始日期之差)。

 public long getExecutionTime() {
 return finishDate.getTime()-startDate.getTime();
 }

 

9.覆蓋toString()方法,返回執行緒的建立日期和執行日期。

 @Override
 public String toString(){
 StringBuilder buffer=new StringBuilder();
 buffer.append(getName());
 buffer.append(": ");
 buffer.append(" Creation Date: ");
 buffer.append(creationDate);
 buffer.append(" : Running time: ");
 buffer.append(getExecutionTime());
 buffer.append(" Milliseconds.");
 return buffer.toString();
 }

 

10.建立一個實現ThreadFactory介面的MyThreadFactory類。

 public class MyThreadFactory implements ThreadFactory {

 

11.宣告一個私有的、int型別的屬性counter。

 private int counter;

 

12.宣告一個私有的、String型別的屬性prefix。

 private String prefix;

 

13.實現這個類的構造器,初始化它的屬性。

 public MyThreadFactory (String prefix) {
 this.prefix=prefix;
 counter=1;
 }

 

14.實現newThread()方法。建立一個MyThread物件並增加counter屬性值。

 @Override
 public Thread newThread(Runnable r) {
 MyThread myThread=new MyThread(r,prefix+"-"+counter);
 counter++;
 return myThread;
 }

 

15.建立一個實現Runnable介面的MyTask類。實現run()方法,令當前執行緒睡眠2秒。

 public class MyTask implements Runnable {
 @Override
 public void run() {
 try {
 TimeUnit.SECONDS.sleep(2);
 } catch (InterruptedException e) {
 e.printStackTrace();
 }
 }
 }

 

16.實現這個例子的主類,通過建立Main類,並實現main()方法。

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

 

17.建立一個MyThreadFactory物件。

 MyThreadFactory myFactory=new MyThreadFactory("MyThreadFactory");

 

18.建立一個Task物件。

 MyTask task=new MyTask();

 

19.使用這個工廠的newThread()方法,建立一個MyThread物件來執行任務。

 Thread thread=myFactory.newThread(task);

 

20.啟動這個執行緒並等待它的結束。

 thread.start();
 thread.join();

 

21.使用toString()方法,寫入關於執行緒的資訊。

 System.out.printf("Main: Thread information.\n");
 System.out.printf("%s\n",thread);
 System.out.printf("Main: End of the example.\n");

 

它是如何工作的…

在這個指南中,你已經通過繼承Thread類來實現自定義的MyThread類。這個類有3個屬性用來儲存:建立日期、執行的開始日期和執行的結束日期。你已實現getExecutionTime()方法,使用開始日期和結束日期屬性,返回執行緒已執行任務的時間。最後,你已覆蓋toString()方法來產生關於執行緒的資訊。

一旦你有自己的執行緒類,你已實現一個工廠來建立這個實現了ThreadFactory介面的類的物件。如果你要使用你的工廠作為一個獨立的物件,這個介面的使用並不是強制的,但是如果你想要用這個工廠使用Java併發API的其他類,你必須通過實現這個介面來構建你的工廠。ThreadFactory介面只有一個方法,newThread()方法接收一個Runnable物件作為引數,並且返回一個用來執行Runnable物件的Thread物件。在你的例子中,你返回一個MyThread物件。

檢查這兩個類,你已實現MyTask類,這個類實現了Runnable物件。這是將在由MyThread物件管理的執行緒中執行的任務。一個MyTask例項令它的執行執行緒睡眠2秒。

在這個例子的主方法中,你已使用MyThreadFactory工廠建立一個MyThread物件,用來執行一個Task物件。執行這個程式,你將看到一條關於開始日期和執行緒執行的執行時間的資訊。

以下截圖顯示這個例子產生的輸出:

2

不止這些…

Java併發API提供Executors類來產生執行緒執行者,通常是ThreadPoolExecutor類的物件。你也可以使用defaultThreadFactory()方法,讓這個類來獲取ThreadFactory介面最基本的實現。這個方法產生的工廠所產生的基本Thread物件都屬性同一個ThreadGroup物件。

你可以在你的程式中使用ThreadFactory介面用於任何目的,不一定要與執行者框架(Executor framework)有關。