start() 和 run() 方法启动线程的区别 ?

结论:

  • start() 方法会启动一个新的线程,以及线程的一些准备工作(状态检查,加入通知线程组),然后 Java 虚拟机调用此线程的 run() 方法;
  • run() 方法是直接执行 Runnable 对象的 run() 方法,是 main 线程下的一个普通线程,并不是多线程执行;

源码分析(Java8):

/**
* 使该线程开始执行;Java 虚拟机将调用此线程的 <code>run</code> 方法。
* 结果是两个线程同时运行:当前线程(从调用返回到<code>start</code>方法)和另一个线程(执行其<code>run</code>方法)。
* 多次启动一个线程永远是不合法的。特别是,线程一旦完成执行就可能不会被重新启动。
* @exception  IllegalThreadStateException 如果线程已经启动,会抛出 java.lang.IllegalThreadStateException
* @see        #run()
* @see        #stop()
*/
public synchronized void start() {
    
    
    /**
        * VM 不会为 main() 方法线程或系统线程组 created/set 调用此方法。
        * 将来添加到此方法的任何新功能可能也必须添加到 VM。
        * "0" 状态值对应的线程状态为 "NEW"。
        */
    if (threadStatus != 0)
        throw new IllegalThreadStateException();

    /**
    * 通知组该线程将要启动,以便可以将其添加到组的线程列表中,并且可以减少改组的未启动计数。
    */
    group.add(this);

    boolean started = false;
    try {
    
    
        start0();
        started = true;
    } finally {
    
    
        try {
    
    
            if (!started) {
    
    
                group.threadStartFailed(this);
            }
        } catch (Throwable ignore) {
    
    
            /**
                * 什么也不做,如果 start0() 方法抛出 Throwable,则它将被向上传递到调用调用堆栈。
                */
        }
    }
}

private native void start0();


/**
* 如果此线程是使用单独的<code>Runnable</code>运行对象构造的,
* 则将调用该<code>Runnable</code>对象的<code>run</code>方法;否则,此方法不执行任何操作返回。
* <code>Thread</code>的子类应重写此方法。
*/
@Override
public void run() {
    
    
    if (target != null) {
    
    
        target.run();
    }
}

start() 方法分析:

  1. 首先检查线程状态 threadStatus 是否为 0,0 状态代表线程的 “NEW” 状态,不为 0 会抛出 IllegalThreadStateException 异常;
  2. 将线程加入通知组;
  3. 然后调用一个 native 类型的 start0() 方法,此方法会在 VM 中调用此线程的 run() 方法,使线程进入 READY 状态;

run()方法分析:

  1. 检查 target(Runnable 对象)是否为空,不为空时直接调用 Runnable 的 run() 方法,只是main线程下一个普通线程,并不是多线程。

猜你喜欢

转载自blog.csdn.net/dejunyang/article/details/111596811