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

正确答案:两种

  • 实现Runnable接口
  • 继承Thread类

1.1 Thread类中的run()

Thread类的源码:

private Runnable target;@Overridepublic 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类。