天天看点

定制并发类(四)实现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)有关。 

继续阅读