关于java并发:并发基础第01章实现线程的正确方式

2次阅读

共计 2611 个字符,预计需要花费 7 分钟才能阅读完成。

1. 问题的引出:实现线程有几种形式?2 种?5 种?

正确答案:两种

  • 实现 Runnable 接口
  • 继承 Thread 类

1.1 Thread 类中的 run()

Thread 类的源码:

private Runnable target;
@Override
public void run() {if (target != null) {target.run();
    }
}

Thread 类有个 Runnable 的 target 援用,如果结构器传入了 target 且不为 null,就执行它的 run(); 但前提是它有机会执行 – 什么意思呢?

1.2 既实现了 Thread 又实现了 Runnable 接口执行谁的 run()

且看如下一段代码:MyTask 类是 Runnable 接口的实现;MyThread 是 Thread 类的子类;如果初始化 MyThread 时把 MyTask 作为 Runnable 传入到 target,会执行谁的 run()?

package com.niewj.basic.createthread;

/**
 * 既实现 Runnable 又继承 Thread
 *
 * @author niewj
 * @description
 * @copyright © 2022 niewj.com
 * @department 研发
 * @date 2023/1/3 23:14
 */
public class RunnableThread {public static void main(String[] args) {
        // 1. 实现了 Runnable
        MyTask task = new MyTask();
        // 2. 实现了 Runnable,也继承了 Thread, thread2 输入什么?Thread thread = new MyThread(task);
        thread.start();}


    // MyThread 是继承 Thread 的类
    static class MyThread extends Thread {public MyThread(Runnable runnable) {super(runnable);
        }

        @Override
        public void run() {System.out.println("==============MyThread.run()====");
        }
    }

    // MyTask 是实现 Runnable 的接口
    static class MyTask implements Runnable {
        @Override
        public void run() {System.out.println("==============Runnable.run()====");
        }
    }
}

执行后果如下:可见执行了 Thread 的 run() 而不是 Runnable 的;
这里比拟蛊惑的是,不是说 target!=null 就执行它的 run() 吗?要害是这里不是判断 target 的问题,而是整个 Thread 子类的 run() 办法被子类笼罩了,没有机会执行到 MyThread 父类 Thread 的 run() 办法了,这才是要害!

==============MyThread.run()====

1.3 简写成如下的代码再了解一遍:

package com.niewj.basic.createthread;

/**
 * 既实现 Runnable 又继承 Thread
 *
 * @author niewj
 * @description
 * @copyright © 2022 niewj.com
 * @department 研发
 * @date 2023/1/3 23:14
 */
public class RunnableThread {public static void main(String[] args) {
        // 1. 实现了 Runnable
        Thread thread = new Thread(() -> System.out.println("==============Runnable.run()====")) {
            @Override
            public void run() {System.out.println("==============MyThread.run()====");
            }
        };
        // 2. 实现了 Runnable,也继承了 Thread, thread2 输入什么?thread.start();}
}

控制台:

==============MyThread.run()====

是子类 run() 笼罩了 Thread 的 run(),所以 Thread 类的 run() 中的逻辑都不会执行到。

2. 实现线程形式的其余说法

  1. 说法 1:Callable 接口
  2. 说法 2: 线程池形式
  3. 说法 3: 定时器类

2.1 Callable 接口

Callable 接口自身并不会创立线程,最终还是借用了 Runnable 接口来实现线程的作用。别忘了 Callable 接口的用法:

  • Callable 接口要寄生在 FutureTask 里

    Callable 接口要寄生在 FutureTask 里能力实现线程, 最终靠的也是 Runnable,因为 FutureTask 是 Runnable 接口的子类。所以只能说 Callable 是借 Runnable 实现一次复出而已;

还有说 Executors 里应用 Callable,实际上也是应用 ThreadPoolExecutor 线程池来实现,外部也是 FutureTask,实质上也一样!

2.2 Executors 和线程池 ThreadPoolExecutor

Executors 是一个线程池的便捷工具类,外部的办法实质上还是通过持了线程池 ExecutorService 的刀来抢的线程的劫,而 ExecutorService 就是线程池的形象接口,它对于线程的实现,也是靠线程创立工厂,最终在 ThreadPoolExecutor 里也是通过 Runnable 接口和 new Thread 来实现的。

2.3 定时器类实现线程的说法

2.3.1 TimerTask 抽象类

TimerTask 抽象类自身也是 Runnable 的实现类,就不用说了,见源码:

public abstract class TimerTask implements Runnable {}

2.3.2 Timer 类

Timer 类中是持有一个 TimerThread 类,TimerThread 类呢是 Thread 的子类,实质上也是 Thread:

private final TimerThread thread = new TimerThread(queue);
class TimerThread extends Thread {}

所以,最终还是只有两种形式实现线程:实现 Runnable 接口和集成 Thread 类。

正文完
 0