聊一聊多线程的 run() 和 start(),挖一挖start0

x33g5p2x  于2021-11-21 转载在 其他  
字(1.5k)|赞(0)|评价(0)|浏览(217)

首先是结论,应该大家知道:
调用start() 会触发多线程执行 ;

调用run() 还是当做执行了一个普通方法,没有多线程执行。

start()示例:

public class MyThread extends Thread {
    @SneakyThrows
    @Override
    public void run(){
        sleep(5000);
        System.out.println("run 内容打印 ");
    }

    public static void main(String[] args) {
        System.out.println("start 调用");
        MyThread testThread1=new MyThread();
        new Thread(testThread1,"线程1").start();
        System.out.println("主线程 最后的输出");
        
    }
}

结果:

run()示例:

public class MyThread extends Thread {
    @SneakyThrows
    @Override
    public void run(){
        sleep(5000);
        System.out.println("run 内容打印 ");
    }

    public static void main(String[] args) {
        System.out.println("run 调用");
        MyThread testThread2=new MyThread();
        new Thread(testThread2,"线程2").run();
        System.out.println("主线程 最后的输出");

    }
}

结果:

也就是咱们在使用多线程的时候要注意,调用run()是不正确的,不是我们想要的多线程效果。

那么我们应该调用 start() 。

我想问, 为什么?

为什么调用  start() 就是多线程  ?

ok,进入这篇文章的主题,一起挖源码 。

先看看java里面 start()的源码注释 :
使该线程开始执行;Java虚拟机 调用此线程的  run 方法。

结果是两个线程同时运行:

当前线程 start 和另一个线程(执行其运行方法)。

不用多说,大概也是告诉我们这个方法调用之后,是会触发多线程执行。

再看看start方法,里面调用了 start0() ,然后没了。

那么可以知道 关键在于 start0() 。

可以看到这个start0 方法被 native 修饰着 。

native 关键字告诉编译器(其实是JVM)调用的是该方法在外部定义,这里指的是C。

也就是说光看java的源码是没办法找到 start0 ()的。

没事,既然进到我的文章,绝不会就此结束 。

openJDK源码 在线查阅地址 :
jdk8/jdk8/jdk: 687fd7c7986d /src/

锁定Thread.c

来看看我们想找的相关源码,发现目标 start0:

在这里大致能知道,调用的是JVM的StartThread函数 。

也就是说我们需要去挖JVM的代码 ,Java 8, 使用的是 Oracle 的64位HotSpot虚拟机。

所以我直接下载HotSpot 源码。

锁定HotSpot 源码 :

找源码的过程我就省略了, 给出一些核心点,

可以看到里面 调用了 JavaThread :

再看看 JavaThread  :

看到这里,基本就差不多了锁定了 真的新创建了一个线程   create_thread 

大致就挖到这吧。可能这篇文章对大家帮助不大,但是对于跟我一样看源码有强迫症的人,多多少少心里会舒坦一些哈哈。

相关文章