Java实现线程的2种正确方法

2020-06-17  本文已影响0人  _灯火阑珊处

准确的讲,创建线程只有一种方式,那就是构造Thread类,而实现线程的执行单元(run()方法)有两种方式

方法1:继承Thread类,重写Thread的run方法
方法2:实现Runnable接口的run方法,并把Runnable实例传给Thread类

Oracle官方文档说明:

https://docs.oracle.com/javase/8/docs/api/java/lang/Thread.html

Oracle官方文档截图

第一种(继承Thread类)

public class ThreadStyle extends Thread {

    public static void main(String[] args) {
        new ThreadStyle().start();
    }

    @Override
    public void run() {
        System.out.println("继承Thread方法");
    }
}

第二种(实现Runnable接口)

public class RunnableStyle implements Runnable {

    public static void main(String[] args) {
        new Thread(new RunnableStyle()).start();
    }

    @Override
    public void run() {
        System.out.println("实现Runnable接口方法");
    }
}

实现Runnable接口和继承Thread类哪种方式更好

  1. 从代码架构角度:
    这里分为两件事情,第一件事情是具体的任务(也就是run()方法里的内容)
    第二件事情是跟整个线程生命周期相关的,比如说创建线程、运行线程、销毁线程等,这个是Thread类去做的事情。
    这两个事情目的不一样,所以从代码架构角度应该是解耦的,所以实现Runnable接口更好
  2. 新建线程的损耗:
    继承Thread类,每次想新建任务,只能去新建一个独立的线程,而新建独立线程损耗是比较大的;使用Runnable可以使用线程池等工具,利用工具就能减少创建线程、销毁线程带来的损耗。
  3. 对于扩展性而言,Java不支持双继承
    综上所述:实现Runnable接口比继承Thread类更好

两种方法的本质对比

Thread类中run()方法源码

public class Thread implements Runnable {
    ……
    ……
    此处省略

    /* What will be run. */
    private Runnable target;

    ……

    /**
     * If this thread was constructed using a separate
     * <code>Runnable</code> run object, then that
     * <code>Runnable</code> object's <code>run</code> method is called;
     * otherwise, this method does nothing and returns.
     * <p>
     * Subclasses of <code>Thread</code> should override this method.
     *
     * @see     #start()
     * @see     #stop()
     * @see     #Thread(ThreadGroup, Runnable, String)
     */
    @Override
    public void run() {
        if (target != null) {
            target.run();
        }
    }

    ...
    ...
    ...
    
}

  1. 方法1(继承Thread类)run()方法整个都被重写;
  2. 方法2(实现Runnable接口)传递进来一个target(target就是Runnable对象),判断target不为null,最后调用target.run();
  3. 本质上两种方法最后都是调用run()方法。

如果同时使用两种方法启动线程?

public class BothRunnableThread {
    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("我来自Runnable");
            }
        }) {
            @Override
            public void run() {
                System.out.println("我来自Thread");
            }
        }.start();
    }
}

控制台会打印什么?
运行结果:

我来自Thread

为什么“我来自Runnable”没有输出?
因为new Thread创建了一个匿名内部类,传入了一个Runnable对象,

new Runnable() {
    @Override
    public void run() {
        System.out.println("我来自Runnable");
    }
}

之后又重写了run()方法,

@Override
public void run() {
    System.out.println("我来自Thread");
}

最后调用start()去运行,
但是重写了run()方法,导致下面3行代码也没了,

if (target != null) {
    target.run();
}

所以即便是传入了Runnable对象,它的target.run();也不会执行

上一篇 下一篇

猜你喜欢

热点阅读