1. 继承关系不同
1.1 继承Thread类
// 直接继承Thread类
class MyThread extends Thread {
@Override
public void run() {
System.out.println("线程执行中...");
}
}
// 使用
MyThread thread = new MyThread();
thread.start();
1.2 实现Runnable接口
// 实现Runnable接口
class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("线程执行中...");
}
}
// 使用
Thread thread = new Thread(new MyRunnable());
thread.start();
2. 主要区别对比
| 特性 | 继承Thread类 | 实现Runnable接口 |
|---|---|---|
| 继承限制 | 占用了唯一的继承机会,无法再继承其他类 | 不占用继承机会,可以继承其他类 |
| 代码复用 | 线程和任务绑定在一起,复用性差 | 任务与线程分离,复用性好 |
| 资源共享 | 多个线程需要创建多个对象实例 | 多个线程可以共享同一个Runnable实例 |
| 设计原则 | 不符合面向对象设计原则 | 符合"组合优于继承"的原则 |
| 复杂度 | 相对简单直接 | 需要创建Thread对象来包装 |
3. 资源共享的差异
3.1 继承Thread方式 - 资源不共享
class TicketThread extends Thread {
private int tickets = 5; // 每个线程都有自己的tickets
@Override
public void run() {
while(tickets > 0) {
System.out.println(getName() + "卖出票号:" + tickets--);
}
}
}
// 测试 - 每个线程独立售票,总共卖出15张票
new TicketThread().start();
new TicketThread().start();
new TicketThread().start();
3.2 继承Thread方式 - 资源不共享
class TicketRunnable implements Runnable {
private int tickets = 5; // 多个线程共享同一个tickets
@Override
public void run() {
while(tickets > 0) {
System.out.println(Thread.currentThread().getName() + "卖出票号:" + tickets--);
}
}
}
// 测试 - 三个线程共享5张票
TicketRunnable task = new TicketRunnable();
new Thread(task, "窗口1").start();
new Thread(task, "窗口2").start();
new Thread(task, "窗口3").start();
4. 使用场景
4.1 适合继承Thread的场景
- 需要重写Thread类的方法(如interrupt()等)
- 简单的单线程任务,不需要复杂的类层次结构
- 快速原型开发
4.2 适合实现Runnable的场景(推荐)
- 需要继承其他类
- 需要在线程间共享资源
- 使用线程池(线程池只能接受Runnable或Callable任务)
- 符合面向对象设计原则
- 复杂的业务逻辑处理
5. 现代开发的最佳实践
5.1 使用Lambda表达式(Java 8+)
// 更简洁的写法
new Thread(() -> {
System.out.println("使用Lambda创建线程");
}).start();
5.2 使用线程池 + Runnable
ExecutorService executor = Executors.newFixedThreadPool(5);
// 提交Runnable任务
executor.execute(() -> {
System.out.println("线程池执行任务");
});
executor.shutdown();
5.3 实现Callable接口(有返回值)
class MyCallable implements Callable<String> {
@Override
public String call() throws Exception {
return "任务执行结果";
}
}
// 使用
Future<String> future = executor.submit(new MyCallable());
String result = future.get();
6. 总结
实现Runnable接口是更被推荐的方式,主要原因:
- 灵活性更高: 不占用继承位置,可以继承其他类
- 资源共享方便: 多个线程可以共享同一个Runnable实例
- 符合设计原则: 任务与执行机制分离
- 与现代API兼容: 线程池、CompletableFuture等都接受Runnable
- 代码更清晰: 业务逻辑与线程控制分离
在实际开发中,除非有特殊需求需要重写Thread类的方法,否则都应该优先选择实现Runnable接口的方式来创建线程。
Runnable与Thread的区别

被折叠的 条评论
为什么被折叠?



