首先是结论,应该大家知道:
调用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
大致就挖到这吧。可能这篇文章对大家帮助不大,但是对于跟我一样看源码有强迫症的人,多多少少心里会舒坦一些哈哈。