核心结论一句话总结
start(): 启动一个新线程,JVM 会在该线程中自动调用run()方法,实现了真正的多线程。run(): 只是一个普通的方法,如果直接调用它,它会在当前线程中执行,不会启动新的线程,是单线程行为。
详细解释与代码示例
为了更好地理解,我们通过一个具体的例子来看。

start() 方法的作用
当你调用一个线程对象的 start() 方法时,会发生两件事:
- 创建一个新的线程:JVM 会为这个线程分配独立的内存空间、程序计数器、栈等资源。
- 调用
run()方法:这个新创建的线程会开始执行其run()方法中的代码。
关键点:run() 方法是在新线程的上下文中执行的,因此它与调用 start() 的线程是并发执行的。
run() 方法的本质
run() 方法是 Thread 类中的一个普通实例方法,它的定义如下:
public void run() {
if (target != null) {
target.run();
}
}
如果你直接调用 myThread.run(),run() 方法里的代码会像调用任何其他普通方法一样,在当前正在执行的线程中顺序执行,并不会创建新的线程。

代码对比示例
下面这个例子将清晰地展示二者的区别。
class MyTask implements Runnable {
@Override
public void run() {
// 获取当前正在执行此代码的线程对象
Thread currentThread = Thread.currentThread();
System.out.println("run() 方法开始执行,线程名: " + currentThread.getName() + ", ID: " + currentThread.getId());
try {
// 模拟耗时任务
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("run() 方法执行完毕,线程名: " + currentThread.getName() + ", ID: " + currentThread.getId());
}
}
public class StartVsRunDemo {
public static void main(String[] args) {
MyTask myTask = new MyTask();
Thread myThread = new Thread(myTask);
System.out.println("主线程开始,线程名: " + Thread.currentThread().getName());
// --- 情况一:调用 start() ---
System.out.println("\n--- 调用 start() ---");
myThread.start(); // 启动新线程
// --- 情况二:调用 run() ---
System.out.println("\n--- 调用 run() ---");
// myThread.run(); // 直接调用 run() 方法
System.out.println("主线程继续执行,线程名: " + Thread.currentThread().getName());
}
}
运行结果分析
取消注释 myThread.start();,注释掉 myThread.run();
主线程开始,线程名: main
--- 调用 start() ---
主线程继续执行,线程名: main
run() 方法开始执行,线程名: Thread-0, ID: 13
run() 方法执行完毕,线程名: Thread-0, ID: 13
分析:
- 主线程(main 线程)启动后,执行到
myThread.start()。 start()方法启动了一个新的线程,我们称之为 "Thread-0"。- 关键点:主线程和 "Thread-0" 是并发执行的,所以主线程不会等待 "Thread-0" 执行完,而是继续往下打印 "主线程继续执行..."。
- "Thread-0" 线程在稍后(可能是几毫秒后)开始执行
run()方法中的代码,你可以看到run()方法中的Thread.currentThread().getName()返回的是 "Thread-0",而不是 "main"。
取消注释 myThread.run();,注释掉 myThread.start();

主线程开始,线程名: main
--- 调用 run() ---
run() 方法开始执行,线程名: main, ID: 1
run() 方法执行完毕,线程名: main, ID: 1
主线程继续执行,线程名: main
分析:
- 主线程执行到
myThread.run()。 - 这只是一个普通的方法调用,
run()方法中的代码在主线程中直接、顺序地执行。 - 主线程会阻塞,直到
run()方法执行完毕后,才会继续执行下面的System.out.println("主线程继续执行...");。 - 你可以看到
run()方法中的Thread.currentThread().getName()返回的是 "main",证明它是在主线程中运行的。
总结表格
| 特性 | thread.start() |
thread.run() |
|---|---|---|
| 作用 | 启动一个新的线程,并让该线程执行 run() 方法。 |
直接调用 run() 方法本身。 |
| 线程创建 | 是,会创建一个新的执行线程。 | 否,没有创建新线程。 |
| 执行上下文 | run() 方法中的代码在新创建的线程中执行。 |
run() 方法中的代码在调用它的当前线程中执行。 |
| 并发性 | 实现了多线程,主线程和新线程可以并发执行。 | 没有实现多线程,代码是顺序执行的。 |
| 调用方式 | 只能通过 start() 方法来触发新线程的执行。 |
run() 只是一个普通方法,可以像任何其他方法一样被直接调用。 |
| 典型错误 | - | 误以为 myThread.run() 会启动一个新线程来执行任务。 |
最佳实践
当你希望一段代码在后台异步、并发地执行时,你应该:
- 创建一个
Runnable对象(或者继承Thread类,但通常不推荐)。 - 将这个
Runnable对象包装在一个Thread对象中。 - 调用这个
Thread对象的start()方法。
永远不要直接调用 run() 方法来期望实现多线程效果。
