实现 ThreadFactory 接口来生成自定义线程

工厂模式是一个创造模式,它的目标是开发一个类,此类的任务是创建一个或多个类的对象。 然后,当要创建这些类其中一个类的对象时,使用工厂代替使用 new 操作符。

  • 使用工厂集中了对象的创建,有以下好处:
    • 容易改变创建的对象的类
    • 容易改变创建对象的方式
    • 易于限制使用受限资源的对象的创建(例如一个类型只能有N个对象)
    • 容易生成对象创建的统计数据

Java 提供了 ThreadFactory 接口来实现一个 Thread 对象工厂。 Java Concurrency API 的某些高级工具,如 Executor 框架或 Fork/Join 框架,使用线程工厂来创建线程。

Java Concurrency API 中工厂模式的另一个例子是 Executor 类。它提供了很多方法来创建不同种类的 Executor 对象。

任务

扩展 Thread 类增加一些新功能。实现一个线程工厂来创建该类的线程。

实现

本节的示例代码在 com.elanzone.books.noteeg.chpt7.sect04 package中

  • 线程扩展类 : MyThread : extends Thread

    • 属性 creationDate, startDate, finishDate : 都为 Date 类型,分别表示线程的 创建、开始、结束时间
    • 辅助方法 setCreationDate(), setStartDate(), setFinishDate(): 分别设置 creationDate, startDate, finishDate 为当前时间
    • 在构造函数中调用 setCreationDate() 方法设置 creationDate 为当前时间
            private Date creationDate;
            private Date startDate;
            private Date finishDate;
    
            public MyThread(Runnable target, String name) {
                super(target, name);
                setCreationDate();
            }
    
            private void setCreationDate() {
                creationDate = new Date();
            }
    
            private void setStartDate() {
                startDate = new Date();
            }
    
            private void setFinishDate() {
                finishDate = new Date();
            }
    
    • run() 方法:在调用父类的run()方法前后分别调用 setStartDate() 和 setFinishDate() 设置线程的开始、停止时间
            @Override
            public void run() {
                setStartDate();
                super.run();
                setFinishDate();
            }
    
    • getExecutionTime() : 获取线程的执行时间(停止时间与开始时间之间的时长)
            public long getExecutionTime() {
                return finishDate.getTime() - startDate.getTime();
            }
    
    • 覆盖 toString() 方法,返回线程的名称和创建、开始、停止时间信息
            @Override
            public 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();
            }
    
  • 线程工厂实现类 :MyThreadFactory : implements ThreadFactory

    • 属性 counter : int 类型 :用于统计创建的线程总数
    • 属性 prefix : String 对象 : 用作线程名称的前缀
    • 在构造函数中初始化 prefix 属性为参数值,counter 属性值为 1
            private int counter;
            private String prefix;
    
            public MyThreadFactory(String prefix) {
                this.prefix = prefix;
                counter = 1;
            }
    
    • 覆盖 newThread() 方法: 创建 MyThread 对象(线程名称为前缀加counter)后 counter 加1
            @Override
            public Thread newThread(Runnable r) {
                MyThread myThread = new MyThread(r, prefix + "-" + counter);
                counter++;
                return myThread;
            }
    
  • Runnable 实现类 : MyTask

    • run() 方法:睡上2秒
            @Override
            public void run() {
                try {
                    TimeUnit.SECONDS.sleep(2);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
    
  • 控制类 :Main

    1. 创建一个 MyThreadFactory 对象 factory
    2. 创建一个 MyTask 对象 task
    3. 调用 MyThreadFactory 对象的 newThread() 方法创建一个线程
    4. 启动线程并等待线程结束
    5. 输出线程信息
            MyThreadFactory factory=new MyThreadFactory("MyThreadFactory");
            MyTask task = new MyTask();
    
            Thread thread = factory.newThread(task);
    
            thread.start();
            try {
                thread.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            System.out.printf("Main: Thread information.\n");
            System.out.printf("%s\n",thread);
            System.out.printf("Main: End of the example.\n");
    

讲解

在本节中实现了一个扩展 Thread 类的定制的 MyThread 类。此类有3个属性保存创建时间、开始运行的时间和结束运行的时间。 使用开始时间和结束时间属性,实现了 getExecutionTime() 方法返回线程执行任务的时间。 最后覆盖了 toString() 方法来生成关于线程的信息。

有了自己的线程类后,实现 ThreadFactory 接口实现了一个工厂来创建该线程类的对象。 如果您作为一个独立的对象来使用此工厂,则不一定要实现 ThreadFactory 接口。 但是如果您要和 Java Concurrency API 的其他类一起所使用此工厂,您必须实现 ThreadFactory 接口。 ThreadFactory 接口只有一个方法 newThread(),其参数是一个 Runnable 对象,返回一个 Thread 对象来执行该 Runnable 对象。 本例中,返回一个 MyThread 对象。

为了检查这2个类,实现了 MyTask 类(此类实现 Runnable 接口)。此任务将在 MyThread 对象管理的线程中执行。 一个 MyTask 实例让运行它的线程睡上2秒钟。

在本例的 main 方法中,用一个 MyThreadFactory 对象创建了一个 MyThread 对象来运行一个 MyTask 对象。 运行此程序,您将看到执行的线程的开始时间和运行时间的信息。

了解更多

Java Concurrency API 提供了 Executors 类来生成线程执行者,通常是 ThreadPoolExecutor 类对象。 您也可以用 Executors 类的 defaultThreadFactory() 方法来获得ThreadFactory接口的最基本的实现。 此方法生成的工厂生成基本的 Thread 对象都属于同一个 ThreadGroup 对象。