Java Thread中的start() 和 run()方法对比

start() 和 run()

start()

  • 调用start方法,只是通知 jvm有一个线程要启动,让其在有空的时候启动线程,至于何时启动线程并不是start能决定的,最终启动线程的时间点是由线程调度器决定的。所以线程启动的顺序并不是由调用start方法的顺序决定的,这也说明了为什么有时候后调用start方法的线程会先启动。(start只负责通知 jvm启动,具体什么时候启动由线程调度器说了算
  • 调用start方法,涉及两个线程,一个是主线程,即调用start方法的线程,另一个是要启动的线程(新创建的线程)。
  • start方法的执行流程
    • (1)检查线程状态,只有在new状态下的线程才能继续,否则抛出IllegalThreadStateException(在运行中或者已经结束的线程,都不能再次启动);
    • (2)被加入线程组;
    • (3)调用 start0() 方法启动线程;

注意:
(1)start方法是被synchronized修饰的方法,可以保证线程安全。
(2)由 jvm 创建的main方法线程和system组线程,并不会通过start来启动。

Thread.java 中start方法的源码如下:

public synchronized void start() {
    // 如果线程不是"新建状态(new)",则抛出异常!
    if (threadStatus != 0)
        throw new IllegalThreadStateException();

    // 将线程添加到ThreadGroup中
    group.add(this);
    
    boolean started = false;
    try {
        // 通过start0()启动线程
        start0();
        // 设置started标记
        started = true;
    } finally {
        try {
            if (!started) {
                group.threadStartFailed(this);
            }
        } catch (Throwable ignore) {
        }
    }
}

start()实际上是通过本地方法start0()启动线程的。而start0()会新运行一个线程,新线程会调用run()方法。

private native void start0();

run()

如果直接调用 run() ,那么 run() 只是一个普通的方法而已,和线程的生命周期无关,程序中依然只有主线程这一个线程,其程序执行路径还是只有一条,还是要顺序执行,还是要等待run方法体执行完毕后才可继续执行下面的代码,这些就没有达到实现多线程的目的。

Thread.java中run的源码如下:

public void run() {
    if (target != null) {
        target.run();
    }
}

target是一个Runnable接口的实现类的对象。run()就是直接调用Thread线程的Runnable实现类对象的run()方法,并不会新建一个线程。

两者区别及总结

  • start() : 用start方法来启动线程,真正实现了多线程运行,其无需等待run方法体代码执行完毕而直接继续执行下面的代码。通过调用Thread类的start()方法来启动一个线程,这时此线程处于就绪(可运行)状态并没有运行,一旦得到cpu时间片,就开始执行run()方法,这里方法 run()称为线程体,它包含了要执行的这个线程的内容,run方法运行结束,此线程随即终止;
  • run():run()方法只是类的一个普通方法而已,如果直接调用Run方法,程序中依然只有主线程这一个线程,其程序执行路径还是只有一条,还是要顺序执行还是要等待run方法体执行完毕后才可继续执行下面的代码,这样就没有达到写线程的目的。

start() 才是真正启动一个线程的方法,启动线程不能直接调用run方法,应该调用start方法,来间接地调用run方法启动线程。

/**
 * 对比start和run方法两种方式启动线程
 */
public class StartAndRunMethod {
   public static void main(String[] args) {
      //使用lambdab表达式创建Runnable接口实现类的实例
      Runnable runnable = ()->{
         System.out.println(Thread.currentThread().getName());
      };
      /*
      直接调用run方法,那么这时run方法只是一个普通的方法而已,
      程序中依然只有主线程一个线程,所以这里执行的是主线程(main)
       */
      runnable.run();//这样并不是执行新建的线程,这里执行的是主线程(main)

      /*
      调用start可能并不会立马启动线程,start只是告诉jvm有一个线程要启动,
      让其有空的时候启动。
      最终决定线程的启动时间点是由线程调度器决定。
       */
      new Thread(runnable).start();
   }
}

运行结果:

main
Thread-0

参考:
Java Thread 的 run() 与 start() 的区别
Java多线程系列–“基础篇”03之 Thread中start()和run()的区别

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章