美文网首页
Java实现线程的2种正确方法

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

作者: _灯火阑珊处 | 来源:发表于2020-06-17 13:32 被阅读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();也不会执行

相关文章

  • ThreadPoolExecutor线程池原理

    本文参考Java线程池---addWorker方法解析Java线程池ThreadPoolExecutor实现原理线...

  • Java 实现线程的方式有几种方式?带有返回值的线程怎么实现?

    Java 实现线程的方式有几种方式?带有返回值的线程怎么实现? 在Java线程开发中,有几种方法开启线程?假如需要...

  • Java多线程-实例解析

    Java多线程实例 3种实现方法 Java中的多线程有三种实现方式: 1.继承Thread类,重写run方法。Th...

  • Java并发

    使用线程 Java中有三种使用线程的方法: 实现 Runnable 接口; 实现 Callable 接口; 继承 ...

  • ExecutorService的正确关闭方法

    [翻译][Java]ExecutorService的正确关闭方法 虽然使用ExecutorService可以让线程...

  • 2.Thread和Runnable

    创建线程的两种方法: 继承Thread,Thread也实现了Runnable 实现Runnable java线程的...

  • Java 面试题

    java多线程实现主线程等待子线程执行完问题 1、使用Thread的join()方法,join()方法会阻塞主线程...

  • 线程和线程池

    线程 在java中实现线程的方式: 继承Thread类 实现Runable接口。 main方法其实也是一个线程。在...

  • 线程

    1.实现线程: java中有两种方法可以实现线程,分别是继承Thread类与实现Runnable接口; 修饰线程同...

  • Java多线程之线程池(ThreadPoolExecutor)实

    在上一篇文章Java中实现多线程的3种方法介绍和比较中,我们讲解了Java中实现多线程的3种方法。使用多线程,就必...

网友评论

      本文标题:Java实现线程的2种正确方法

      本文链接:https://www.haomeiwen.com/subject/qdcntktx.html