Java多线程带你用不一样的思维看创建线程的两种方式

Posted 写Bug的渣渣高

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java多线程带你用不一样的思维看创建线程的两种方式相关的知识,希望对你有一定的参考价值。

文章目录

创建线程的两种方式

通过实现 Runnable 接口

public class CreateThread 
//  继承 Thread 类来
    static class MyThread extends Thread
        @Override
        public void run() 
            System.out.println("Hello MyThread");
        
    

//  实现 Runnable 接口:这个方式更灵活,因为实现接口后,可以继承其他类
    static class MyRun implements Runnable
        @Override
        public void run() 
            System.out.println("Hello MyRun");
        
    



    public static void main(String[] args) 
        new MyThread().start();
        new Thread(new MyRun()).start();
        new Thread(()->
            System.out.println("hello lambda!");
        ).start();
    


上面是主流的创建线程的两种方法,那么我们看一下这两种方法有什么区别吧
Runnable:可以看到使用 Runnable 来创建线程,使用 Runnable 接口引向一个匿名内部类,该内部类重写了 Runnable 接口的run方法,再次之后,仍需要创建一个新的线程,然后传入 runnable ;
Thread : 直接继承 Thread 然后重写 run 方法

从面对对象的角度来思考:
两种方法都是为了构造一个 Thread 类,大家可以看到实现了 runnable 接口后,仍然是创建了一个新的线程,把接口作为 Thread 的构造方法参数传入

public Thread(Runnable target) 
    init(null, target, "Thread-" + nextThreadNum(), 0);

start 和 run 方法解析

在初次使用的时候,大家很容易看见,我们重写的是 run 方法,那么为什么调用的时候,调用的却是 start 方法

start启动新线程:通知JVM,有空闲就创建新线程,何时创建由线程调度器控制(并非调用start方法就会创建,即两个调用start的方法顺序不代表线程的创建顺序)

调用完start后,在主线程中启动

    public synchronized void start() 
        /**
         * This method is not invoked for the main method thread or "system"
         * group threads created/set up by the VM. Any new functionality added
         * to this method in the future may have to also be added to the VM.
         *
         * A zero status value corresponds to state "NEW".
         */
        if (threadStatus != 0)
            throw new IllegalThreadStateException();

        /* Notify the group that this thread is about to be started
         * so that it can be added to the group's list of threads
         * and the group's unstarted count can be decremented. */
        group.add(this);

        boolean started = false;
        try 
            start0();
            started = true;
         finally 
            try 
                if (!started) 
                    group.threadStartFailed(this);
                
             catch (Throwable ignore) 
                /* do nothing. If start0 threw a Throwable then
                  it will be passed up the call stack */
            
        
    

为什么不能调用 run 方法 调用了会发生什么事情

public static void main(String[] args) 
    Runnable runnable = ()->
        System.out.println(Thread.currentThread().getName());
    ;
    runnable.run();

    new Thread(runnable).start();

main:因为在调用的时候,我们使用的是接口.方法,实际上 runnable 接口指向一个匿名内部类,这个类重写了 run 方法,我们在调用的时候,调用的是普通方法 run ,并且是在主函数里面调用的 主线程就是 main
Thread-0 :

重复调用 start 方法会发生什么事情

Exception in thread “main” java.lang.IllegalThreadStateException
at java.lang.Thread.start(Thread.java:708)
at StartTwice.main(StartTwice.java:5)

为什么不能重复调用
原因:一旦开始线程完毕,会进入终止状态,无法回退

if (threadStatus != 0)
 throw new IllegalThreadStateException();

threadStatus:
Java 线程状态,已初始化以指示线程“尚未启动”

彩蛋:同时用两种方法来实现同一个线程,会遇到什么

大家可能没有考虑过,如果new Thread 类,并且传入一个 runnable 重写 runnable 接口的 run 方法的同时,重写Thread 类的 run 方法会发生什么事情

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,
两种,一种是重写run方法,一种是给run传入target

我们看看源码,才能知道为什么调用的是 Thread 类的 run

如果该线程是使用单独的 unnable 运行对象构造的,则调用该 Runnable 对象的run 方法;否则,此方法不执行任何操作并返回。  Thread 的子类应覆盖此方法。
 private Runnable target;
@Override
public void run() 
    if (target != null) 
        target.run();
    

解释一下 targer 是我们使用 runnable 方法来构建Thread 类时传入的参数。
这个三行代码是什么,大家思考一下,这个是 Thread 类的 run 方法,我们平时使用的新建 Thread 创建线程,就会重写这个方法,即这个三行代码是被重写的,不会调用。但是如果仅仅只是 runnable 新建线程,我们只是重写了 Runnable 接口的 run 方法,启动线程 Thread 调用的就是未被重写的 这三行Thread 类的run方法中的语句。但两者都有时,Thread 的 run 方法就会被前者覆盖,上方的 run 方法中三行代码永远不会执行

小知识:调用start方法,线程就会立刻启动吗?

  1. 调用了 start 方法,线程就立刻启动了吗???

在调用 start 方法后,其实先通知JVM,让其有空闲就创建新线程,但是何时真正创建由线程调度器决定。即,在某些情况下,可能会出现先 start 的线程后执行

以上是关于Java多线程带你用不一样的思维看创建线程的两种方式的主要内容,如果未能解决你的问题,请参考以下文章

Java中实现多线程的两种方式之间的区别

Java 创建线程的两种方法

如何创建并运行java线程

Java多线程——创建线程的两种方式

java中创建线程的两种方式有啥区别

java中多线程的两种创建方式