start 方法和 run 方法的主要区别是什么?

参考回答

在 Java 中,start()run() 方法都与线程的启动相关,但它们有明显的区别:

  1. start() 方法
    • 用于启动一个新线程,真正创建一个新的执行路径(即新线程)。
    • 调用 start() 后,JVM 会调用线程的 run() 方法,并由系统调度该线程运行。
  2. run() 方法
    • 只是线程的一个普通方法,直接调用时并不会启动新线程,而是在当前线程中以普通方法的方式执行。

关键区别

  • start() 方法会创建新线程并执行 run() 方法。
  • 直接调用 run() 方法不会创建新线程,run() 方法的逻辑会在当前线程中执行。

详细讲解与拓展

1. start() 方法的行为

调用 start() 方法会触发以下流程:

  1. 创建新线程并分配系统资源。
  2. 将线程状态从 NEW(新建) 改为 RUNNABLE(就绪)
  3. JVM 调用线程的 run() 方法,开始执行线程任务。

示例:

public class StartExample {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> System.out.println("Running in a new thread!"));
        thread.start(); // 启动一个新线程
        System.out.println("Main thread is running!");
    }
}

输出可能为:

Main thread is running!
Running in a new thread!

这里主线程和新线程并发执行,顺序可能不确定。


2. run() 方法的行为

如果直接调用 run() 方法:

  • 线程不会启动新执行路径。
  • run() 方法的代码将在当前线程中执行,与普通方法调用无异。

示例:

public class RunExample {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> System.out.println("Running in the current thread!"));
        thread.run(); // 直接调用 run 方法
        System.out.println("Main thread is running!");
    }
}

输出顺序一定是:

Running in the current thread!
Main thread is running!

因为这里的 run() 方法在主线程中同步执行,没有并发。


3. 总结区别

方法 行为 是否创建新线程
start() 启动一个新线程,并调用 run() 方法。
run() 在当前线程中执行 run() 方法的逻辑,与普通方法调用无异。

4. 常见误区

误区 1:直接调用 run() 可以启动线程
  • 实际上,直接调用 run() 只是一个普通方法调用,不会创建新线程。

示例:

Thread thread = new Thread(() -> System.out.println(Thread.currentThread().getName()));
thread.run(); // 输出 "main"
thread.start(); // 输出 "Thread-0"
误区 2:调用 start() 后线程立即执行
  • start() 只是让线程进入就绪状态(RUNNABLE),具体什么时候执行由操作系统调度决定。

5. 注意事项

  1. start() 方法只能调用一次: 如果尝试多次调用 start(),会抛出 IllegalThreadStateException
    Thread thread = new Thread(() -> {});
    thread.start(); // 第一次调用,正常
    thread.start(); // 第二次调用,抛出异常
    
  2. run() 方法可以多次调用: 因为它是普通方法,但不会创建新线程。


6. 拓展知识

start()run() 的底层实现
  • start()

    • 调用的是本地方法 start0(),通过操作系统分配资源,真正启动线程。

    • 源码片段(JDK 8):

    public synchronized void start() {
        if (threadStatus != 0)
            throw new IllegalThreadStateException();
        group.add(this);
        start0(); // 本地方法,启动线程
    }
    
  • run()

    • 是线程执行任务的逻辑代码。
    • 如果直接调用,程序只是在当前线程中顺序执行,没有多线程特性。

7. 什么时候直接使用 run()

尽管在大多数场景中我们使用 start() 方法启动新线程,但在某些测试或单线程模拟场景下,可以直接调用 run()

  • 用于测试线程任务的逻辑,而无需创建线程。
  • 用于无需多线程执行的简单任务。

8. 小结

  • start() 启动新线程,让线程独立运行。
  • run() 普通方法调用,在当前线程中执行。

发表评论

后才能评论