我们先看一个简单例子
java
public class SimpleExample {
public static void main(String[] args) {
System.out.println("=== 故事开始 ===");
// 创建一个"唱歌"任务
Thread singThread = new Thread(() -> {
System.out.println("[唱歌线程] 开始唱歌...");
try {
Thread.sleep(3000); // 唱3秒钟
} catch (Exception e) {}
System.out.println("[唱歌线程] 唱完歌了");
});
System.out.println("\n--- 第1次测试:用run() ---");
System.out.println("[主线程] 调用singThread.run()");
singThread.run(); // 调用run()
System.out.println("[主线程] run()调用完毕");
System.out.println("\n--- 第2次测试:用start() ---");
// 重新创建线程(因为一个Thread对象只能start一次)
singThread = new Thread(() -> {
System.out.println("[唱歌线程] 开始唱歌...");
try {
Thread.sleep(3000);
} catch (Exception e) {}
System.out.println("[唱歌线程] 唱完歌了");
});
System.out.println("[主线程] 调用singThread.start()");
singThread.start(); // 调用start()
System.out.println("[主线程] start()调用完毕");
// 主线程等一会儿,看看效果
try {
Thread.sleep(5000);
} catch (Exception e) {}
System.out.println("\n=== 故事结束 ===");
}
}
运行结果对比
=== 故事开始 ===
--- 第1次测试:用run() ---
主线程\] 调用singThread.run() \[唱歌线程\] 开始唱歌... (这里会卡住3秒钟,因为Thread.sleep(3000)) \[唱歌线程\] 唱完歌了 \[主线程\] run()调用完毕 --- 第2次测试:用start() --- \[主线程\] 调用singThread.start() \[主线程\] start()调用完毕 ← 注意!这里立即输出,没有等待! \[唱歌线程\] 开始唱歌... (这里主线程继续运行,唱歌在后台进行) === 故事结束 === \[唱歌线程\] 唱完歌了 ← 可能在这里输出,因为唱得慢
最关键的区别
- 卡不卡的区别
-
用run() :程序会卡住3秒 ,因为
Thread.sleep(3000)在当前线程执行 -
用start() :程序不卡,主线程继续运行,唱歌在后台慢慢唱
- 顺序的区别
-
用run():一定是这个顺序:
-
"[唱歌线程] 开始唱歌..."
-
(等待3秒)
-
"[唱歌线程] 唱完歌了"
-
"[主线程] run()调用完毕"
-
-
用start():顺序不确定,可能是:
-
"[主线程] start()调用完毕" ← 先输出!
-
"[唱歌线程] 开始唱歌..." ← 后输出
或者反过来,因为两个线程同时运行
-
再看一个简单的例子
public class MostSimple {
public static void main(String[] args) throws Exception {
Thread t = new Thread(() -> {
System.out.println("我是新线程,我的名字是:" + Thread.currentThread().getName());
});
System.out.println("主线程名字:" + Thread.currentThread().getName());
System.out.println("\n--- 用run() ---");
t.run(); // 注意看输出的线程名!
System.out.println("\n--- 用start() ---");
t.start();
Thread.sleep(100); // 等新线程执行完
}
}
运行结果:
主线程名字:main
--- 用run() ---
我是新线程,我的名字是:main ← 注意!还是main线程!
--- 用start() ---
我是新线程,我的名字是:Thread-0 ← 看!线程名变了!
run() = 你自己干活(当前线程执行代码)
start() = 叫别人干活(创建新线程执行代码)
总结:
-
用run() :代码在当前线程执行,会卡住当前线程
-
用start() :代码在新线程执行,不卡当前线程
-
用run() :输出的线程名不变
-
用start() :输出的线程名会变