Java 创建线程:继承 Thread 子类 vs 实现 Runnable 接口
Java 创建线程:继承 Thread 子类 vs 实现 Runnable 接口
一、两种方式代码示例
方式 1:继承 Thread 类创建线程
通过自定义类继承Thread,重写run()方法,调用start()启动线程。
// 继承Thread子类 class MyThread extends Thread{ @Override public void run() { System.out.println("线程正在执行任务"); } } public class TestThread{ public static void main(String[] args) { MyThread t1 = new MyThread(); t1.start(); } }方式 2:实现 Runnable 接口创建线程
自定义类实现Runnable接口,把任务传入 Thread 对象,再启动线程。
// 实现Runnable接口 class MyTask implements Runnable{ @Override public void run() { System.out.println("线程正在执行任务"); } } public class TestRunnable{ public static void main(String[] args) { MyTask task = new MyTask(); Thread t1 = new Thread(task); t1.start(); } }二、核心区别对比
1. 继承关系不同(最大区别)
- 继承 Thread 类:Java 是单继承,一旦继承了
Thread,就不能再继承其他父类,会限制代码的扩展性。 - 实现 Runnable 接口:只是实现接口,当前类还可以继承别的父类,更加灵活,规避了单继承的限制。
2. 任务资源共享能力不同
- 继承 Thread 类:每创建一个
Thread子类对象,都是独立的线程实例,无法直接共享同一个任务资源,必须借助静态变量才能实现共享。 - 实现 Runnable 接口:多个
Thread对象可以传入同一个 Runnable 任务实例,天然可以共享任务中的成员变量,非常适合多线程售票、计数这类资源共享场景。
资源共享示例(Runnable 方式):
class TicketTask implements Runnable{ private int ticket = 10; @Override public void run() { while(ticket > 0){ ticket--; System.out.println(Thread.currentThread().getName() + "卖出一张票,剩余:"+ticket); } } } public class ShareResource{ public static void main(String[] args) { TicketTask task = new TicketTask(); // 3个线程共用同一个任务对象,共享ticket变量 new Thread(task,"窗口1").start(); new Thread(task,"窗口2").start(); new Thread(task,"窗口3").start(); } }3. 任务与线程解耦程度不同
- 继承 Thread:线程对象和任务代码耦合在一起,线程和任务绑定,一个线程对应一套任务。
- 实现 Runnable:把 ** 任务(Runnable)和执行载体(Thread 线程)** 分离开,任务可以被任意多个线程复用,代码解耦更好。
4. 代码复用性
- 继承 Thread:线程类只能作为线程运行,复用性弱。
- 实现 Runnable:Runnable 只是普通任务类,既可以交给 Thread 执行,也可以交给线程池执行,通用性更强。
三、总结优缺点
表格
| 对比项 | 继承 Thread 子类 | 实现 Runnable 接口 |
|---|---|---|
| 继承限制 | 受 Java 单继承约束,不能再继承其他类 | 无继承限制,可同时继承父类 + 实现多个接口 |
| 资源共享 | 多个线程无法直接共享任务数据 | 多线程可以共享同一个 Runnable 任务资源 |
| 代码耦合 | 线程与任务强耦合 | 任务和线程解耦,职责分离 |
| 适用场景 | 简单独立的一次性线程任务 | 多线程资源共享、线程池、业务解耦场景 |
开发建议
日常项目开发中,优先使用实现 Runnable 接口的方式创建线程,规避单继承缺陷,同时更好地实现多线程数据共享;只有简单的独立线程任务,才偶尔使用继承 Thread 的写法。
四、拓展:底层原理
两种方式最终都是调用start()来启动线程,由 JVM 自动调用run()方法。
- 继承 Thread:重写的是 Thread 自身的
run(); - 传入 Runnable:Thread 内部会执行传入 Runnable 对象的
run()方法。
一句话总结:继承 Thread 是把线程和任务写在一起;实现 Runnable 是把任务抽离出来,让线程去执行这个任务。
