定制并发类(四)实现ThreadFactory接口生成自定义的线程

简介:

声明:本文是《 Java 7 Concurrency Cookbook 》的第七章,作者: Javier Fernández González     译者:许巧辉

实现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类。

1 public class MyThread extends Thread {

2.声明3个私有的、Date类型的属性:creationDate、startDate和finishDate。

1 private Date creationDate;
2 private Date startDate;
3 private Date finishDate;

3.实现这个类的构造器。它接收名称和要执行的Runnable对象参数。存储线程的创建日期。

1 public MyThread(Runnable target, String name ){
2 super(target,name);
3 setCreationDate();
4 }

4.实现run()方法。存储线程的开始时间,调用父类的run()方法,存储执行的结束时间。

1 method of the parent class, and store the finish date of the execution.
2 @Override
3 public void run() {
4 setStartDate();
5 super.run();
6 setFinishDate();
7 }

5.实现一个方法用来设置creationDate属性值。

1 public void setCreationDate() {
2 creationDate=new Date();
3 }

6.实现一个方法用来设置startDate属性值。

1 public void setStartDate() {
2 startDate=new Date();
3 }

7.实现一个方法用来设置finishDate属性值。

1 public void setFinishDate() {
2 finishDate=new Date();
3 }

8.实现getExecutionTime()方法,用来计算线程的执行时间(结束日期与开始日期之差)。

1 public long getExecutionTime() {
2 return finishDate.getTime()-startDate.getTime();
3 }

9.覆盖toString()方法,返回线程的创建日期和执行日期。

01 @Override
02 public String toString(){
03 StringBuilder buffer=new StringBuilder();
04 buffer.append(getName());
05 buffer.append(": ");
06 buffer.append(" Creation Date: ");
07 buffer.append(creationDate);
08 buffer.append(" : Running time: ");
09 buffer.append(getExecutionTime());
10 buffer.append(" Milliseconds.");
11 return buffer.toString();
12 }

10.创建一个实现ThreadFactory接口的MyThreadFactory类。

1 public class MyThreadFactory implements ThreadFactory {

11.声明一个私有的、int类型的属性counter。

1 private int counter;

12.声明一个私有的、String类型的属性prefix。

1 private String prefix;

13.实现这个类的构造器,初始化它的属性。

1 public MyThreadFactory (String prefix) {
2 this.prefix=prefix;
3 counter=1;
4 }

14.实现newThread()方法。创建一个MyThread对象并增加counter属性值。

1 @Override
2 public Thread newThread(Runnable r) {
3 MyThread myThread=new MyThread(r,prefix+"-"+counter);
4 counter++;
5 return myThread;
6 }

15.创建一个实现Runnable接口的MyTask类。实现run()方法,令当前线程睡眠2秒。

01 public class MyTask implements Runnable {
02 @Override
03 public void run() {
04 try {
05 TimeUnit.SECONDS.sleep(2);
06 catch (InterruptedException e) {
07 e.printStackTrace();
08 }
09 }
10 }

16.实现这个例子的主类,通过创建Main类,并实现main()方法。

1 public class Main {
2 public static void main(String[] args) throws Exception {

17.创建一个MyThreadFactory对象。

1 MyThreadFactory myFactory=new MyThreadFactory("MyThreadFactory");

18.创建一个Task对象。

1 MyTask task=new MyTask();

19.使用这个工厂的newThread()方法,创建一个MyThread对象来执行任务。

1 Thread thread=myFactory.newThread(task);

20.启动这个线程并等待它的结束。

1 thread.start();
2 thread.join();

21.使用toString()方法,写入关于线程的信息。

1 System.out.printf("Main: Thread information.\n");
2 System.out.printf("%s\n",thread);
3 System.out.printf("Main: End of the example.\n");

它是如何工作的…

在这个指南中,你已经通过继承Thread类来实现自定义的MyThread类。这个类有3个属性用来存储:创建日期、执行的开始日期和执行的结束日期。你已实现getExecutionTime()方法,使用开始日期和结束日期属性,返回线程已执行任务的时间。最后,你已覆盖toString()方法来产生关于线程的信息。

一旦你有自己的线程类,你已实现一个工厂来创建这个实现了ThreadFactory接口的类的对象。如果你要使用你的工厂作为一个独立的对象,这个接口的使用并不是强制的,但是如果你想要用这个工厂使用Java并发API的其他类,你必须通过实现这个接口来构建你的工厂。ThreadFactory接口只有一个方法,newThread()方法接收一个Runnable对象作为参数,并且返回一个用来执行Runnable对象的Thread对象。在你的例子中,你返回一个MyThread对象。

检查这两个类,你已实现MyTask类,这个类实现了Runnable对象。这是将在由MyThread对象管理的线程中执行的任务。一个MyTask实例令它的执行线程睡眠2秒。

在这个例子的主方法中,你已使用MyThreadFactory工厂创建一个MyThread对象,用来执行一个Task对象。执行这个程序,你将看到一条关于开始日期和线程执行的执行时间的信息。

以下截图显示这个例子产生的输出:

2

不止这些…

Java并发API提供Executors类来产生线程执行者,通常是ThreadPoolExecutor类的对象。你也可以使用defaultThreadFactory()方法,让这个类来获取ThreadFactory接口最基本的实现。这个方法产生的工厂所产生的基本Thread对象都属性同一个ThreadGroup对象。

你可以在你的程序中使用ThreadFactory接口用于任何目的,不一定要与执行者框架(Executor framework)有关。

文章转自 并发编程网-ifeve.com

目录
相关文章
|
20小时前
|
Java
【JavaEE】——多线程常用类
Callable的call方法,FutureTask类,ReentrantLock可重入锁和对比,Semaphore信号量(PV操作)CountDownLatch锁存器,
|
20小时前
|
Java 程序员 调度
【JavaEE】线程创建和终止,Thread类方法,变量捕获(7000字长文)
创建线程的五种方式,Thread常见方法(守护进程.setDaemon() ,isAlive),start和run方法的区别,如何提前终止一个线程,标志位,isinterrupted,变量捕获
|
20小时前
|
安全 Java API
【JavaEE】多线程编程引入——认识Thread类
Thread类,Thread中的run方法,在编程中怎么调度多线程
|
1月前
|
安全 Java
线程安全的艺术:确保并发程序的正确性
在多线程环境中,确保线程安全是编程中的一个核心挑战。线程安全问题可能导致数据不一致、程序崩溃甚至安全漏洞。本文将分享如何确保线程安全,探讨不同的技术策略和最佳实践。
41 6
|
1月前
|
安全 Java 开发者
Java 多线程并发控制:深入理解与实战应用
《Java多线程并发控制:深入理解与实战应用》一书详细解析了Java多线程编程的核心概念、并发控制技术及其实战技巧,适合Java开发者深入学习和实践参考。
57 6
|
1月前
|
存储 安全 Java
Java多线程编程中的并发容器:深入解析与实战应用####
在本文中,我们将探讨Java多线程编程中的一个核心话题——并发容器。不同于传统单一线程环境下的数据结构,并发容器专为多线程场景设计,确保数据访问的线程安全性和高效性。我们将从基础概念出发,逐步深入到`java.util.concurrent`包下的核心并发容器实现,如`ConcurrentHashMap`、`CopyOnWriteArrayList`以及`BlockingQueue`等,通过实例代码演示其使用方法,并分析它们背后的设计原理与适用场景。无论你是Java并发编程的初学者还是希望深化理解的开发者,本文都将为你提供有价值的见解与实践指导。 --- ####
|
3天前
|
NoSQL Redis
单线程传奇Redis,为何引入多线程?
Redis 4.0 引入多线程支持,主要用于后台对象删除、处理阻塞命令和网络 I/O 等操作,以提高并发性和性能。尽管如此,Redis 仍保留单线程执行模型处理客户端请求,确保高效性和简单性。多线程仅用于优化后台任务,如异步删除过期对象和分担读写操作,从而提升整体性能。
12 1
|
2月前
|
存储 消息中间件 资源调度
C++ 多线程之初识多线程
这篇文章介绍了C++多线程的基本概念,包括进程和线程的定义、并发的实现方式,以及如何在C++中创建和管理线程,包括使用`std::thread`库、线程的join和detach方法,并通过示例代码展示了如何创建和使用多线程。
60 1
|
2月前
|
Java 开发者
在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口
【10月更文挑战第20天】在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口。本文揭示了这两种方式的微妙差异和潜在陷阱,帮助你更好地理解和选择适合项目需求的线程创建方式。
32 3
|
2月前
|
Java 开发者
在Java多线程编程中,选择合适的线程创建方法至关重要
【10月更文挑战第20天】在Java多线程编程中,选择合适的线程创建方法至关重要。本文通过案例分析,探讨了继承Thread类和实现Runnable接口两种方法的优缺点及适用场景,帮助开发者做出明智的选择。
25 2