Java 创建线程:继承 Thread 子类 vs 实现 Runnable 接口

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 是把任务抽离出来,让线程去执行这个任务。