这里有一道经典的面试题:“一个线程两次调用start()方法会出现什么情况?”,咱们这次结合案例从线程源码的角度炒剩饭。

答:Java的线程是不允许启动两次的,第二次调用时,线程可能处于终止或者其它(非NEW)状态,必然会抛出IllegalThreadStateException,这是一种运行时异常,多次调用start被认为是编程错误。如果业务需要线程run中的代码再次执行,请重新启动一个线程实例。

应聘的时候回答这么多就可以了,下面从源码角度深入分析为什么不行,如果面试官刨根问底,咱们也可以底气十足。

案例分析

package com.sc.register;

/**
 * 在同一线程上两次调用start方法
 *
 * @author Wiener
 * @date 2021/4/9
 */
public class ReStartThread implements Runnable {
    @Override
    public void run() {
        System.out.println("In run() method.");
    }

    public static void main(String[] args) {
        ReStartThread obj = new ReStartThread();
        Thread thread1 = new Thread(obj, "Thread-ReStart");
        thread1.start();
        System.out.println("当前线程状态是:" + thread1.getState());
        // will throw java.lang.IllegalThreadStateException at runtime
        thread1.start();
    }
}

执行结果如下:

当前线程状态是:RUNNABLE
in run() method, method completed.
Exception in thread "main" java.lang.IllegalThreadStateException
	at java.base/java.lang.Thread.start(Thread.java:794)
	at com.sc.register.ReStartThread.main(ReStartThread.java:22)

Process finished with exit code 1

线程源码分析

Thread类中,start()函数第一行代码就是校验线程状态,如果状态不是新建,则抛出运行时异常IllegalThreadStateException,而且备注里有声明:

    /**
     * Java thread status for tools, default indicates thread 'not yet started'
     */
    private volatile int threadStatus;

    public synchronized void start() {
        /**
         * This method is not invoked for the main method thread or "system"
         * group threads created/set up by the VM. Any new functionality added
         * to this method in the future may have to also be added to the VM.
         *
         * A zero status value corresponds to state "NEW".
         */
        if (threadStatus != 0)
            throw new IllegalThreadStateException(); // ①

在①处打断点,以debug模式启动案例,可以看到第二个start()执行后,线程状态 threadStatus 不为0,故抛出异常。调试结果如下图所示:

https://img2020.cnblogs.com/blog/1208468/202104/1208468-20210417145317729-1644574999.png

温馨提示:threadStatus的值在不同机器的运行结果可能不一样。