1. 程式人生 > >實現ThreadFactory介面生成自定義執行緒

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

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

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

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

考慮到在建立具有有限資源的物件時所遇到的限制,在工廠模式中將對物件建立集中化,因此在更改建立的物件類或者物件方式上更有優勢。例如,只有一個型別的N個物件,就能夠輕鬆地生成關於物件建立的統計資料。

Java提供ThreadFactory介面來實現Thread物件工廠。Java併發API中一些高階功能,例如fork/join的Executor框架,就使用執行緒工廠建立執行緒。Java併發API中裡一個工廠模式的例子是Executors類,它提供了大量建立不同類別的Executor物件的方法。本節將通過繼承Thread類新增新功能,實現一個新的執行緒工廠類來生成執行緒。

準備工作

本範例通過Eclipse開發工具實現。如果使用諸如NetBeans的開發工具,開啟並建立一個新的Java專案。

實現過程

通過如下步驟實現範例:

  1. 建立名為MyThread的類,繼承Thread類:

    public class MyThread extends 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介面:

    public class MyThreadFactory implements ThreadFactory{
    
  10. 宣告名為counter的私有AtomicInteger屬性:

    	private AtomicInteger counter;
    
  11. 宣告名為prefix的私有String屬性:

    	private String prefix;
    
  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物件:

    		MyThreadFactory myFactory=new MyThreadFactory("MyThreadFactory");
    
  17. 建立Task物件:

    		MyTask task=new MyTask();
    
  18. 使用工廠的newThread()方法建立MyThread物件,用來執行任務:

    		Thread thread=myFactory.newThread(task);
    
  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物件。如果執行本範例,將會看到執行緒啟動時間和執行緒執行時間的資訊。

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

pics/08_02.jpg

擴充套件學習

Java併發API提供Executors類來生成執行緒執行器,通常是ThreadPoolExecutor類的物件。還可以使用此類獲得ThreadFactory介面的最基本實現,通過使用defaultThreadFactory()方法。此方法生成的工廠建立屬於同一個ThreadGroup物件的基本執行緒物件,ThreadFactory介面可以用於任何目的,不只是與Executor框架相關。