1位工作6年的小伙伴去某里P6一面,被问到这样一道面试题,说,为什么启动一个线程不直接调用run()方法,而要调用start()方法来启动,如果调用两次start()会有什么后果?
如果,你被问到这样一道面试,你能回答出来吗?今天,我给大家来分享一下,我对这个问题的理解。
1、run()和start()的区别
首先回答为什么启动线程不能直接调用run()方法,而要调用start()方法,我从以下4个方面来回答:
第1:start()方法是Java线程约定的内置方法,能够确保代码在新的线程上下文中运行。
第2:start()方法包含了触创建新线程的特殊代码逻辑。run()方法是我们自己写的代码,很显然没有这个能力。
第3:如果直接调用run()方法,那么它只是一个普通的方法调用,程序中依然只有一个主线程,并且只能顺序执行,需要等待run()方法执行结束后才能继续执行后面的代码。
第4:我们创建线程的目的是为了更充分地利用CPU资源,如果直接调用run()方法,就失去了创建线程的意义了。
2、调用两次start()的后果
了解了run()方法和start()方法的区别,那如果调用两次start()方法会有什么后果呢?在Java中,线程的start()方法只能被调用一次,如果第二次调用会抛出 IllegalThreadStateException,这是一种运行时异常,多次调用 start 被认为是编程错误。
在Java中,线程的运行状态被定义成了5个枚举值,分别是:
(1)新建(NEW),线程已经创建好了,但是还没有调用start()方法启动。
(2)就绪(RUNNABLE),这个状态下的线程可能正在运行,也可能还在就绪队列里面,等待系统分配CPU资源。
在操作系统中,会额外区分一种状态叫做RUNNING,但是从 Java API 的角度,并不能表示出来。
(3)阻塞(BLOCKED),表示线程处于等待Monitor Lock的状态。
(4)等待(WAITING),表示线程处于条件等待状态,当触发条件后会唤醒。比如wait/notify等。
(5)计时等待(TIMED_WAIT),它和WAITING状态是一样的,只是多了一个超时条件触发机制。
(6)终止(TERMINATED),表示线程执行结束。
在Java API 中,影响线程运行状态的因素,如图所示:
在我们第一次调用 start() 方法的时候,线程可能处于终止或者其他非 NEW的状态,再次调用start()方法的时候,相当于让这个正在运行的线程重新运行一遍。不管是从线程安全的角度来看,还是从线程本身的执行逻辑来看,它都是不合理的。
因此,为了避免这个问题出现,Java会先去判断当前线程的运行状态。
好了,以上就是我对Java线程的start()方法和run()方法的理解。