天天看點

定制并發類(四)實作ThreadFactory接口生成自定義的線程

實作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類。

<code>1</code>

<code>public</code> <code>class</code> <code>mythread</code><code>extends</code> <code>thread {</code>

2.聲明3個私有的、date類型的屬性:creationdate、startdate和finishdate。

<code>private</code> <code>date creationdate;</code>

<code>2</code>

<code>private</code> <code>date startdate;</code>

<code>3</code>

<code>private</code> <code>date finishdate;</code>

3.實作這個類的構造器。它接收名稱和要執行的runnable對象參數。存儲線程的建立日期。

<code>public</code> <code>mythread(runnable target, string name ){</code>

<code>super</code><code>(target,name);</code>

<code>setcreationdate();</code>

<code>4</code>

<code>}</code>

4.實作run()方法。存儲線程的開始時間,調用父類的run()方法,存儲執行的結束時間。

<code>method of the parent</code><code>class</code><code>, and store the finish date of the execution.</code>

<code>@override</code>

<code>public</code> <code>void</code> <code>run() {</code>

<code>setstartdate();</code>

<code>5</code>

<code>super</code><code>.run();</code>

<code>6</code>

<code>setfinishdate();</code>

<code>7</code>

5.實作一個方法用來設定creationdate屬性值。

<code>public</code> <code>void</code> <code>setcreationdate() {</code>

<code>creationdate=</code><code>new</code> <code>date();</code>

6.實作一個方法用來設定startdate屬性值。

<code>public</code> <code>void</code> <code>setstartdate() {</code>

<code>startdate=</code><code>new</code> <code>date();</code>

7.實作一個方法用來設定finishdate屬性值。

<code>public</code> <code>void</code> <code>setfinishdate() {</code>

<code>finishdate=</code><code>new</code> <code>date();</code>

8.實作getexecutiontime()方法,用來計算線程的執行時間(結束日期與開始日期之差)。

<code>public</code> <code>long</code> <code>getexecutiontime() {</code>

<code>return</code> <code>finishdate.gettime()-startdate.gettime();</code>

9.覆寫tostring()方法,傳回線程的建立日期和執行日期。

<code>01</code>

<code>02</code>

<code>public</code> <code>string tostring(){</code>

<code>03</code>

<code>stringbuilder buffer=</code><code>new</code> <code>stringbuilder();</code>

<code>04</code>

<code>buffer.append(getname());</code>

<code>05</code>

<code>buffer.append(</code><code>": "</code><code>);</code>

<code>06</code>

<code>buffer.append(</code><code>" creation date: "</code><code>);</code>

<code>07</code>

<code>buffer.append(creationdate);</code>

<code>08</code>

<code>buffer.append(</code><code>" : running time: "</code><code>);</code>

<code>09</code>

<code>buffer.append(getexecutiontime());</code>

<code>10</code>

<code>buffer.append(</code><code>" milliseconds."</code><code>);</code>

<code>11</code>

<code>return</code> <code>buffer.tostring();</code>

<code>12</code>

10.建立一個實作threadfactory接口的mythreadfactory類。

<code>public</code> <code>class</code> <code>mythreadfactory</code><code>implements</code> <code>threadfactory {</code>

11.聲明一個私有的、int類型的屬性counter。

<code>private</code> <code>int</code> <code>counter;</code>

12.聲明一個私有的、string類型的屬性prefix。

<code>private</code> <code>string prefix;</code>

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

<code>public</code> <code>mythreadfactory (string prefix) {</code>

<code>this</code><code>.prefix=prefix;</code>

<code>counter=</code><code>1</code><code>;</code>

14.實作newthread()方法。建立一個mythread對象并增加counter屬性值。

<code>public</code> <code>thread newthread(runnable r) {</code>

<code>mythread mythread=</code><code>new</code> <code>mythread(r,prefix+</code><code>"-"</code><code>+counter);</code>

<code>counter++;</code>

<code>return</code> <code>mythread;</code>

15.建立一個實作runnable接口的mytask類。實作run()方法,令目前線程睡眠2秒。

<code>public</code> <code>class</code> <code>mytask</code><code>implements</code> <code>runnable {</code>

<code>try</code> <code>{</code>

<code>timeunit.seconds.sleep(</code><code>2</code><code>);</code>

<code>}</code><code>catch</code> <code>(interruptedexception e) {</code>

<code>e.printstacktrace();</code>

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

<code>public</code> <code>class</code> <code>main {</code>

<code>public</code> <code>static</code> <code>void</code> <code>main(string[] args)</code><code>throws</code> <code>exception {</code>

17.建立一個mythreadfactory對象。

<code>mythreadfactory myfactory=</code><code>new</code> <code>mythreadfactory(</code><code>"mythreadfactory"</code><code>);</code>

18.建立一個task對象。

<code>mytask task=</code><code>new</code> <code>mytask();</code>

19.使用這個工廠的newthread()方法,建立一個mythread對象來執行任務。

<code>thread thread=myfactory.newthread(task);</code>

20.啟動這個線程并等待它的結束。

<code>thread.start();</code>

<code>thread.join();</code>

21.使用tostring()方法,寫入關于線程的資訊。

<code>system.out.printf(</code><code>"main: thread information.\n"</code><code>);</code>

<code>system.out.printf(</code><code>"%s\n"</code><code>,thread);</code>

<code>system.out.printf(</code><code>"main: end of the example.\n"</code><code>);</code>

它是如何工作的…

在這個指南中,你已經通過繼承thread類來實作自定義的mythread類。這個類有3個屬性用來存儲:建立日期、執行的開始日期和執行的結束日期。你已實作getexecutiontime()方法,使用開始日期和結束日期屬性,傳回線程已執行任務的時間。最後,你已覆寫tostring()方法來産生關于線程的資訊。

一旦你有自己的線程類,你已實作一個工廠來建立這個實作了threadfactory接口的類的對象。如果你要使用你的工廠作為一個獨立的對象,這個接口的使用并不是強制的,但是如果你想要用這個工廠使用java并發api的其他類,你必須通過實作這個接口來建構你的工廠。threadfactory接口隻有一個方法,newthread()方法接收一個runnable對象作為參數,并且傳回一個用來執行runnable對象的thread對象。在你的例子中,你傳回一個mythread對象。

檢查這兩個類,你已實作mytask類,這個類實作了runnable對象。這是将在由mythread對象管理的線程中執行的任務。一個mytask執行個體令它的執行線程睡眠2秒。

在這個例子的主方法中,你已使用mythreadfactory工廠建立一個mythread對象,用來執行一個task對象。執行這個程式,你将看到一條關于開始日期和線程執行的執行時間的資訊。

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

定制并發類(四)實作ThreadFactory接口生成自定義的線程

不止這些…

java并發api提供executors類來産生線程執行者,通常是threadpoolexecutor類的對象。你也可以使用defaultthreadfactory()方法,讓這個類來擷取threadfactory接口最基本的實作。這個方法産生的工廠所産生的基本thread對象都屬性同一個threadgroup對象。

你可以在你的程式中使用threadfactory接口用于任何目的,不一定要與執行者架構(executor framework)有關。 

繼續閱讀