Java 9并發程式設計指南 目錄
實作ThreadFactory接口生成自定義線程
- 準備工作
- 實作過程
- 工作原理
- 擴充學習
在面向對象程式設計領域中,工廠模式是廣泛使用的設計模式,創造性的通過開發類來建立一個或多個類的對象。當想要建立其中一個類的對象時,我們使用工廠來代替新的操作符。
考慮到在建立具有有限資源的對象時所遇到的限制,在工廠模式中将對對象建立集中化,是以在更改建立的對象類或者對象方式上更有優勢。例如,隻有一個類型的N個對象,就能夠輕松地生成關于對象建立的統計資料。
Java提供ThreadFactory接口來實作Thread對象工廠。Java并發API中一些進階功能,例如fork/join的Executor架構,就使用線程工廠建立線程。Java并發API中裡一個工廠模式的例子是Executors類,它提供了大量建立不同類别的Executor對象的方法。本節将通過繼承Thread類添加新功能,實作一個新的線程工廠類來生成線程。
準備工作
本範例通過Eclipse開發工具實作。如果使用諸如NetBeans的開發工具,打開并建立一個新的Java項目。
實作過程
通過如下步驟實作範例:
- 建立名為MyThread的類,繼承Thread類:
- 聲明名為creationDate、startDate和finishDate三個私有Date屬性:
private final Date creationDate; private Date startDate; private Date finishDate;
- 實作類構造函數,将name和待執行的Runnable對象作為參數接收。初始化線程的建立時間:
public MyThread(Runnable target, String name ){ super(target,name); creationDate = new Date(); }
- 實作run()方法,存儲線程的起始時間,調用父類的run()方法,存儲執行的結束時間:
@Override public void run() { setStartDate(); super.run(); setFinishDate(); }
- 實作建立startDate屬性值的方法:
public synchronized void setStartDate() { startDate=new Date(); }
- 實作建立finishDate屬性值的方法:
public synchronized void setFinishDate() { finishDate=new Date(); }
- 實作名為getExecutionTime()的方法,通過完成時間與開始時間的內插補點來計算線程的執行時間:
public synchronized long getExecutionTime() { return finishDate.getTime()-startDate.getTime(); }
- 重寫toString()方法,傳回線程的建立時間和執行時間:
@Override public synchronized 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(); } }
- 建立名為MyThreadFactory的類,實作ThreadFactory接口:
- 聲明名為counter的私有AtomicInteger屬性:
- 聲明名為prefix的私有String屬性:
- 實作類構造函數,初始化屬性:
public MyThreadFactory (String prefix) { this.prefix=prefix; counter=new AtomicInteger(1); }
- 實作newThread()方法,建立MyThread對象且遞增counter屬性:
@Override public Thread newThread(Runnable r) { MyThread myThread=new MyThread(r,prefix+"-"+counter.getAndIncrement()); return myThread; } }
- 建立名為MyTask的類來實作Runnable接口,實作run()方法,設定目前線程休眠2秒鐘:
public class MyTask implements Runnable{ @Override public void run() { try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } } }
- 通過建立名為Main的類,添加main()方法,實作本範例主類:
public class Main { public static void main(String[] args) throws Exception {
- 建立MyThreadFactory對象:
- 建立Task對象:
- 使用工廠的newThread()方法建立MyThread對象,用來執行任務:
- 啟動線程,然後等待線程結束:
thread.start(); thread.join();
- 使用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類。此類包含三個屬性,分别存儲線程建立和執行的開始時間,以及線程執行的結束時間。使用開始和結束時間屬性,實作了getExecutionTime()方法,傳回線程在執行任務時消耗的總時間。最後,重寫toString()方法生成線程相關資訊。
一旦線程類自定義後,就通過實作ThreadFactory接口生成一個工廠來建立類對象。如果要将工廠作為獨立對象,則不需要強制使用此接口,但是如果要将此工廠與Java并發API的其他類一起使用,則必須通過實作此接口來建構工廠。ThreadFactory接口隻有一個方法:newThread()方法。此方法将Runnble對象作為參數接收,并傳回Thread對象來執行Runnable對象。本範例中傳回MyThread對象。
為了檢查這兩個類,實作MyTask類,在MyThread對象管理的線程中執行的任務 ,此類實作Runnable接口。一個MyTask執行個體設定其執行線程休眠2秒鐘。
在本範例主方法中,使用執行Task對象的MyThreadFactory工廠來建立MyThread對象。如果執行本範例,将會看到線程啟動時間和線程執行時間的資訊。
下圖顯示本範例在控制台輸出的執行資訊:
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiQTZzUjN5M2Y1EWYwATM0ADOidTYykTNhdTMhVTZzImZ9kXZLVmchh2cmQWYvxmb39GZ9Q2boRXZt9TRwMjQ5YDRFVTMBVkNxgDO0ETN0ATRGNjRzU0M1UzMx8CXlxWam9CXsFmbvNnclB3LclGch9CXzdXevwVbvNmLvFGZ19WeuUGdv52Lc9CX6MHc0RHaiojIsJye.jpg)
擴充學習
Java并發API提供Executors類來生成線程執行器,通常是ThreadPoolExecutor類的對象。還可以使用此類獲得ThreadFactory接口的最基本實作,通過使用defaultThreadFactory()方法。此方法生成的工廠建立屬于同一個ThreadGroup對象的基本線程對象,ThreadFactory接口可以用于任何目的,不隻是與Executor架構相關。