一、Thread 与 Runnable 的区别
1. 核心概念
特性 | Thread | Runnable |
---|
实现方式 | 继承 Thread 类并重写 run() 方法 | 实现 Runnable 接口并实现 run() 方法 |
灵活性 | 单继承限制,无法继承其他类 | 无继承限制,可继承其他类或实现其他接口 |
资源共享 | 每个 Thread 实例独立运行 | 多个线程可共享同一 Runnable 实例 |
推荐使用 | 早期 Java 版本 | 现代 Java 开发(更灵活) |
2. 代码示例
(1) 继承 Thread 类
java
复制
class MyThread extends Thread {@Overridepublic void run() {System.out.println("Thread 方式运行: " + Thread.currentThread().getName());}
}// 使用
public class Main {public static void main(String[] args) {MyThread thread = new MyThread();thread.start(); // 启动新线程(调用 run())}
}
(2) 实现 Runnable 接口
java
复制
class MyRunnable implements Runnable {@Overridepublic void run() {System.out.println("Runnable 方式运行: " + Thread.currentThread().getName());}
}// 使用
public class Main {public static void main(String[] args) {Thread thread = new Thread(new MyRunnable());thread.start(); // 启动新线程(调用 run())}
}
(3) 匿名内部类(简化写法)
java
复制
// Thread 匿名类
new Thread() {@Overridepublic void run() {System.out.println("匿名 Thread 运行");}
}.start();// Runnable 匿名类
new Thread(new Runnable() {@Overridepublic void run() {System.out.println("匿名 Runnable 运行");}
}).start();
二、线程生命周期
1. 线程状态图
复制
新建 (New) → 就绪 (Runnable) → 运行 (Running) → 终止 (Terminated)↑ ↓ ↓└阻塞 (Blocked) ←───────┘
2. 状态说明
状态 | 触发条件 | 示例 |
---|
新建 (New) | 通过 new Thread() 创建线程对象 | Thread thread = new Thread(); |
就绪 (Runnable) | 调用 start() 方法后,等待 CPU 调度 | thread.start(); |
运行 (Running) | 线程获得 CPU 时间片,执行 run() 方法 | 线程正在执行任务 |
阻塞 (Blocked) | 等待资源或锁(如 sleep() 、wait() ) | Thread.sleep(1000); |
终止 (Terminated) | run() 方法执行完毕或线程被强制终止 | 线程任务完成或调用 stop() (不推荐) |
3. 状态转换示例
java
复制
class LifecycleDemo implements Runnable {@Overridepublic void run() {System.out.println("线程启动: " + Thread.currentThread().getName());try {// 进入阻塞状态(睡眠 2 秒)Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("线程终止");}
}public class Main {public static void main(String[] args) {Thread thread = new Thread(new LifecycleDemo());System.out.println("线程状态: " + thread.getState()); // NEWthread.start(); // 进入 RUNNABLESystem.out.println("线程状态: " + thread.getState()); // RUNNABLEtry {// 等待线程执行完毕thread.join();} catch (InterruptedException e) {e.printStackTrace();}System.out.println("最终线程状态: " + thread.getState()); // TERMINATED}
}
三、核心方法与使用场景
1. 常用方法
方法 | 作用 | 示例 |
---|
start() | 启动线程,JVM 调用 run() 方法 | thread.start(); |
run() | 线程执行体(直接调用不会启动新线程) | 重写 run() 方法 |
sleep(millis) | 使线程休眠指定毫秒数 | Thread.sleep(1000); |
join() | 等待线程执行完毕 | thread.join(); |
currentThread() | 获取当前线程对象 | Thread.currentThread().getId(); |
2. 示例:线程休眠与等待
java
复制
class SleepDemo implements Runnable {@Overridepublic void run() {System.out.println("开始执行: " + Thread.currentThread().getName());try {// 休眠 1 秒Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("执行结束: " + Thread.currentThread().getName());}
}public class Main {public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(new SleepDemo());thread.start();// 主线程等待子线程结束thread.join();System.out.println("主线程继续执行");}
}
四、Thread vs Runnable 最佳实践
1. 为何推荐 Runnable?
- 避免单继承限制:Java 类只能继承一个父类,使用
Runnable
可继承其他类。 - 资源共享:多个线程可共享同一
Runnable
实例,适合需要数据共享的场景。 - 解耦:将任务(
Runnable
)与线程(Thread
)分离,提高代码灵活性。
示例:多线程共享资源
java
复制
class Counter implements Runnable {private int count = 0;@Overridepublic void run() {for (int i = 0; i < 5; i++) {count++;System.out.println(Thread.currentThread().getName() + ": " + count);}}
}public class Main {public static void main(String[] args) {Counter counter = new Counter();// 两个线程共享同一 Counter 实例Thread t1 = new Thread(counter, "线程1");Thread t2 = new Thread(counter, "线程2");t1.start();t2.start();}
}
2. Thread 的适用场景
- 需要直接控制线程行为(如设置线程优先级、守护线程)。
- 需要复用线程池中的线程(结合
ExecutorService
)。
五、线程生命周期实战
场景:模拟订单处理流程
java
复制
class OrderProcessor implements Runnable {@Overridepublic void run() {System.out.println("订单处理开始: " + Thread.currentThread().getName());try {// 模拟耗时操作Thread.sleep(3000);} catch (InterruptedException e) {System.out.println("订单处理被中断");return; // 提前终止}System.out.println("订单处理完成: " + Thread.currentThread().getName());}
}public class Main {public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(new OrderProcessor());System.out.println("线程状态: " + thread.getState()); // NEWthread.start();System.out.println("线程状态: " + thread.getState()); // RUNNABLE// 主线程等待 1 秒后中断Thread.sleep(1000);thread.interrupt(); // 发送中断信号thread.join();System.out.println("最终线程状态: " + thread.getState()); // TERMINATED}
}
六、总结
- Thread 与 Runnable:
- Runnable 更灵活,推荐使用;Thread 适合直接控制线程行为。
- 线程生命周期:
- 重点关注 新建 → 就绪 → 运行 → 终止,以及 阻塞 状态的触发条件。
- 核心方法:
start()
启动线程,run()
定义任务,sleep()
和 join()
控制流程。
最佳实践:
- 优先使用
Runnable
+ 线程池(如 ExecutorService
)。 - 避免直接调用
Thread.sleep()
长时间阻塞。 - 处理中断异常(
InterruptedException
),确保线程优雅退出。