终于有时间写 线程8大核心基础知识【2】-- 启动线程的正确和错误方式。
跟我一起学习,一起攻破Java并发吧!
为了美好生活,为了明天,加油!
启动线程的正确和错误方式
start()和run()的比较
- 代码演示
由此可见:Runnable调用的run打印的结果为main主线程,这不是我们想要的,我们的本意是想新创建一个线程,并启动起来。所以我们可以看到直接使用run方法带来的效果是有偏差的,Thread实现的和我们的预想结果一致
start()方法原理解读
方法含义
- 启动新线程
通知我们的JVM,在有空闲的情况下,启动新线程
注:启动新线程不是我们决定的,是线程调度器决定的,所有start()方法调用后,不一定会直接运行,可能等一会才运行,也有可能很长时间不运行如:遇到饥饿的情况
一个start()会牵扯到两个线程
1.主线程
2.创建的线程
调用两次start会怎么样呢?
发现会报错,口说没意思,直接看源码吧!
start()源码解析
- 启动新线程检查线程状态
这个就是刚才报错的罪魁祸首了!如果线程状态不为0,则报异常
那0是什么呢?
查看上面的注释的意思为:java线程状态在初始化时为0,也就是还没有启动
- 加入线程组
- 调用start0()
被native修饰,代表不是java实现的,是有c,c++实现的
分享一下对native的理解:start0()方法是不能直接看源码的,如果想看源码,需要去网上OpenJDK里查看,版本不同,实现可能也不同
run()方法原理解读
直接调用Runnalie实现的run()方法,调用的就是普普通通的方法,和自己写的普通方法无区别,所有刚才的线程执行的线程为主线程。
所以我们要启动线程,不能调用run()方法,而是调用start方法间接调用run方法
常见面试问题
一个线程两次调用start()方法会出现什么情况?为什么?
答:会抛出一个异常,在start()方法最开始的时候,就会对当前的线程状态进行一个检查,如果已经执行了方法,就会抛出这个异常。
还不够,再加上线程的六个状态。
线程的状态使用一个枚举类型来描述的。这个枚举一共有6个值: NEW(新建)、RUNNABLE(运行)、BLOCKED(锁池)、TIMED_WAITING(定时等待)、WAITING(等待)、TERMINATED(终止、结束)。
既然start()方法会调用run()方法,为什么我们会调用start()方法,而不是直接调用run()方法呢?
答:因为调用start()方法才是真正启动一个线程,会经过各个线程的生命周期,如果直接调用run()方法,不过是普通的方法而已,也不会用子线程调用