天天看點

實作ThreadFactory接口生成自定義線程準備工作實作過程工作原理擴充學習

Java 9并發程式設計指南 目錄

實作ThreadFactory接口生成自定義線程

  • 準備工作
  • 實作過程
  • 工作原理
  • 擴充學習

在面向對象程式設計領域中,工廠模式是廣泛使用的設計模式,創造性的通過開發類來建立一個或多個類的對象。當想要建立其中一個類的對象時,我們使用工廠來代替新的操作符。

考慮到在建立具有有限資源的對象時所遇到的限制,在工廠模式中将對對象建立集中化,是以在更改建立的對象類或者對象方式上更有優勢。例如,隻有一個類型的N個對象,就能夠輕松地生成關于對象建立的統計資料。

Java提供ThreadFactory接口來實作Thread對象工廠。Java并發API中一些進階功能,例如fork/join的Executor架構,就使用線程工廠建立線程。Java并發API中裡一個工廠模式的例子是Executors類,它提供了大量建立不同類别的Executor對象的方法。本節将通過繼承Thread類添加新功能,實作一個新的線程工廠類來生成線程。

準備工作

本範例通過Eclipse開發工具實作。如果使用諸如NetBeans的開發工具,打開并建立一個新的Java項目。

實作過程

通過如下步驟實作範例:

  1. 建立名為MyThread的類,繼承Thread類:
  2. 聲明名為creationDate、startDate和finishDate三個私有Date屬性:
    private final Date creationDate;
    	private Date startDate;
    	private Date finishDate;
               
  3. 實作類構造函數,将name和待執行的Runnable對象作為參數接收。初始化線程的建立時間:
    public MyThread(Runnable target, String name ){
    		super(target,name);
    		creationDate = new Date();
    	}
               
  4. 實作run()方法,存儲線程的起始時間,調用父類的run()方法,存儲執行的結束時間:
    @Override
    	public void run() {
    		setStartDate();
    		super.run();
    		setFinishDate();
    	}
               
  5. 實作建立startDate屬性值的方法:
    public synchronized void setStartDate() {
    		startDate=new Date();
    	}
               
  6. 實作建立finishDate屬性值的方法:
    public synchronized void setFinishDate() {
    		finishDate=new Date();
    	}
               
  7. 實作名為getExecutionTime()的方法,通過完成時間與開始時間的內插補點來計算線程的執行時間:
    public synchronized long getExecutionTime() {
    		return finishDate.getTime()-startDate.getTime();
    	}
               
  8. 重寫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();
    	}
    }
               
  9. 建立名為MyThreadFactory的類,實作ThreadFactory接口:
  10. 聲明名為counter的私有AtomicInteger屬性:
  11. 聲明名為prefix的私有String屬性:
  12. 實作類構造函數,初始化屬性:
    public MyThreadFactory (String prefix) {
    		this.prefix=prefix;
    		counter=new AtomicInteger(1);
    	}
               
  13. 實作newThread()方法,建立MyThread對象且遞增counter屬性:
    @Override
    	public Thread newThread(Runnable r) {
    		MyThread myThread=new MyThread(r,prefix+"-"+counter.getAndIncrement());
    		return myThread;
    	}
    }
               
  14. 建立名為MyTask的類來實作Runnable接口,實作run()方法,設定目前線程休眠2秒鐘:
    public class MyTask implements Runnable{
    	@Override
    	public void run() {
    		try {
    			TimeUnit.SECONDS.sleep(2);
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    	}
    }
               
  15. 通過建立名為Main的類,添加main()方法,實作本範例主類:
    public class Main {
    	public static void main(String[] args) throws Exception {
               
  16. 建立MyThreadFactory對象:
  17. 建立Task對象:
  18. 使用工廠的newThread()方法建立MyThread對象,用來執行任務:
  19. 啟動線程,然後等待線程結束:
    thread.start();
    		thread.join();
               
  20. 使用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對象。如果執行本範例,将會看到線程啟動時間和線程執行時間的資訊。

下圖顯示本範例在控制台輸出的執行資訊:

實作ThreadFactory接口生成自定義線程準備工作實作過程工作原理擴充學習

擴充學習

Java并發API提供Executors類來生成線程執行器,通常是ThreadPoolExecutor類的對象。還可以使用此類獲得ThreadFactory接口的最基本實作,通過使用defaultThreadFactory()方法。此方法生成的工廠建立屬于同一個ThreadGroup對象的基本線程對象,ThreadFactory接口可以用于任何目的,不隻是與Executor架構相關。