5. Thread的start()和 run()方法

在 Java 多线程编程中,start() 和 run() 是 Thread 类的两个关键方法,但它们的行为和用途截然不同。以下是它们的核心区别、底层机制及使用场景的详细解析:

1. 核心区别

特性start()run()线程行为启动新线程,触发 JVM 调用 run() 方法。直接在当前线程中执行 run() 的代码,不创建新线程。调用次数限制同一线程对象只能调用一次(否则抛出 IllegalThreadStateException)。可多次调用,无限制。线程生命周期将线程从 NEW 状态转为 RUNNABLE 状态。与普通方法调用无异,不改变线程状态。并发性实现多线程并发执行。串行执行(在当前线程中顺序运行)。

2. 底层机制

(1) start() 方法

行为:

向 JVM 注册新线程,分配线程栈等资源。触发线程调度器将线程状态转为 RUNNABLE(就绪状态)。JVM 自动调用 run() 方法,新线程开始执行任务。 关键源码:public synchronized void start() {

if (threadStatus != 0) // 检查线程状态是否为 NEW

throw new IllegalThreadStateException();

// 将线程添加到线程组

group.add(this);

boolean started = false;

try {

start0(); // 调用 native 方法启动线程

started = true;

} finally {

// 处理启动失败的情况

}

}

private native void start0(); // 依赖底层操作系统实现

(2) run() 方法

行为:

仅执行 run() 方法中定义的代码,不会创建新线程。若直接调用 run(),等同于调用普通方法(由当前线程执行)。 默认实现:@Override

public void run() {

if (target != null) {

target.run(); // 若通过 Runnable 构造线程,执行其 run()

}

}

3. 代码示例与结果对比

示例 1:直接调用 run()

public class RunExample {

public static void main(String[] args) {

Thread thread = new Thread(() -> {

System.out.println("当前线程: " + Thread.currentThread().getName());

});

thread.run(); // 直接调用 run()

System.out.println("主线程: " + Thread.currentThread().getName());

}

}

// 输出:

// 当前线程: main

// 主线程: main

结论:run() 代码由主线程执行,未创建新线程。

示例 2:调用 start()

public class StartExample {

public static void main(String[] args) {

Thread thread = new Thread(() -> {

System.out.println("子线程: " + Thread.currentThread().getName());

});

thread.start(); // 启动新线程

System.out.println("主线程: " + Thread.currentThread().getName());

}

}

// 输出(可能顺序不同):

// 主线程: main

// 子线程: Thread-0

结论:start() 创建新线程,主线程和子线程并发执行。

4. 常见误区与陷阱

误区 1:误用 run() 实现多线程

// 错误示例:期望并发执行,实际串行执行

Thread t1 = new Thread(task1);

Thread t2 = new Thread(task2);

t1.run(); // 在主线程执行

t2.run(); // 继续在主线程执行

陷阱 2:重复调用 start()

Thread thread = new Thread(() -> { /* 任务 */ });

thread.start();

thread.start(); // 抛出 IllegalThreadStateException

5. 设计意义与最佳实践

start() 的用途: 将任务(run())提交给新线程,实现真正的并发或并行(依赖 CPU 核心数)。run() 的用途: 定义线程要执行的任务逻辑,通常不直接调用。

最佳实践:

始终通过 start() 启动线程,除非明确需要在当前线程同步执行任务。避免重写 start() 方法: 若需扩展线程行为,优先重写 run() 或在任务逻辑(Runnable)中实现。使用线程池替代直接创建线程:ExecutorService executor = Executors.newFixedThreadPool(4);

executor.submit(() -> { /* 任务 */ }); // 内部调用 start() 的等效逻辑

6. 总结

方法核心作用线程创建适用场景start()启动新线程,触发异步执行 run()是需要并发/并行执行任务的场景run()定义任务逻辑,直接同步执行代码否测试任务逻辑,或明确需同步执行的代码

核心原则:

多线程并发:必须使用 start()。单线程执行:直接调用 run()(罕见场景)。永远不要混淆两者!