写在开头
在写完上一篇文章Java面试必考题之线程的生命周期,结合源码,透彻讲解! - 掘金 (juejin.cn)后,本以为这个小知识点就总结完了。
但刚刚吃晚饭时,突然想到了多年前自己面试时的亲身经历,决定再回来补充一个小知识点!
记得是一个周末去面试Java后端开发工程师岗位
,面试官针对Java多线程进行了狂轰乱炸般的考问,什么线程创建的方式、线程的状态、各状态间的切换、如果保证线程安全、各种锁的区别,如何使用等等,因为有好好背八股文,所以七七八八的也答上来了,但最后面试官问了一个现在看来很简单,但当时根本不知道的问题,他先是问了我,看过Thread的源码没,我毫不犹豫的回答看过,紧接着他问:
线程在调用了一次start启动后,再调用一次可以不?如果线程执行完,同样再调用一次start又会怎么样?
这个问题抛给你们,请问该如何作答呢?
线程的启动
我们知道虽然很多八股文面试题中说Java创建线程的方式有3种、4种,或者更多种,但实际上真正可以创建一个线程的只有new Thread().start();
【代码示例1】
1 | java复制代码public class Test { |
输出:
1 | java复制代码Thread-0:NEW |
创建一个Thread,这时线程处于NEW状态,这时调用start()方法,会让线程进入到RUNNABLE状态。
RUNNABLE的线程调用start
在上面测试代码的基础上,我们再次调用start()方法。
【代码示例2】
1 | java复制代码public class Test { |
输出:
1 | java复制代码Thread-0:NEW |
第二次调用时,代码抛出IllegalThreadStateException异常。
这是为什么呢?我们跟进start源码中一探究竟!
【源码解析1】
1 | java复制代码// 使用synchronized关键字保证这个方法是线程安全的 |
这里有个threadStatus,若它不等于0表示线程已经启动或结束,直接抛IllegalThreadStateException异常,我们在start源码中打上断点,从第一次start中跟入进去,发现此时没有报异常。
此时的threadStatus=0,线程状态为NEW,断点继续向下走时,走到native方法start0()时,threadStatus=5,线程状态为RUNNABLE。此时,我们从第二个start中进入断点。
这时threadStatus=5,满足不等于0条件,抛出IllegalThreadStateException异常!
TERMINATED的线程调用start
终止状态下的线程,情况和RUNNABLE类似!
【代码示例3】
1 | java复制代码public class Test { |
输出:
1 | java复制代码Thread-0:TERMINATED |
这时同样也满足不等于0条件,抛出IllegalThreadStateException异常!
我们其实可以跟入到state的源码中,看一看线程几种状态设定的逻辑。
【源码解析2】
1 | java复制代码// Thread.getState方法源码: |
总结
OK,今天就讲这么多啦,其实现在回头看看,这仅是一个简单且微小的细节而已,但对于刚准备步入职场的我来说,却是一个难题,今天写出来,除了和大家分享一下Java线程中的小细节外,更多的是希望正在准备面试的小伙伴们,能够心细,多看源码,多问自己为什么?并去追寻答案,Java开发不可浅尝辄止。
结尾彩蛋
如果本篇博客对您有一定的帮助,大家记得留言+点赞+收藏呀。原创不易,转载请联系Build哥!
如果您想与Build哥的关系更近一步,还可以关注“JavaBuild888”,在这里除了看到《Java成长计划》系列博文,还有提升工作效率的小笔记、读书心得、大厂面经、人生感悟等等,欢迎您的加入!
本文转载自: 掘金