美文网首页
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();也不会执行

    相关文章

      网友评论

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

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