核心区别在于设计定位:继承Thread是扩展线程本身,实现Runnable是定义可执行任务;前者受限于单继承且状态隔离,后者支持资源共享、职责分离,推荐日常使用。

核心区别在于设计定位和使用约束:继承 Thread 是把“线程本身”当作类来扩展;实现 Runnable 是把“要做的事”定义为任务,再交给线程去执行。
继承 Thread 类的特点
你写一个类,让它 是 一个线程。这个类直接拥有线程的全部能力(如 start()、getName()、setPriority() 等),但代价明显:
- Java 不支持多继承,一旦继承了
Thread,就无法再继承其他业务类 - 每个线程对象都独占一份实例变量,天然隔离,难以共享状态(比如多个线程想操作同一个计数器,必须额外加同步或传参)
- 逻辑耦合重——任务代码和线程生命周期管理混在一起,不利于复用和测试
实现 Runnable 接口的特点
你写一个类,让它 能被线程执行。它只声明“我要做什么”,不关心“谁来执行我”或“怎么执行”:
- 不受单继承限制,可同时继承业务父类 + 实现
Runnable - 多个
Thread对象可以共用同一个Runnable实例,天然支持资源共享(例如一个票务对象被 5 个售票线程共用) - 职责分离清晰:任务逻辑(
run())与线程调度(Thread.start())解耦,更易单元测试、替换执行器(如后续改用ExecutorService)
关键行为差异:别误调 run() 方法
两者都必须重写 run() 方法,但调用方式决定是否真正启动新线程:
-
threadObj.run()→ 只是普通方法调用,在当前线程里顺序执行,不产生并发 -
threadObj.start()→ JVM 创建新系统线程,并由该线程回调run(),这才是真正的多线程
注意:对 Runnable 实例不能直接调用 start(),必须包装进 Thread 对象(new Thread(runnable).start())。
实际选型建议
除非是极简演示或教学场景,日常开发中优先选择 实现 Runnable:
- 符合面向对象的“组合优于继承”原则
- 为后续升级到线程池(
ExecutorService.submit(Runnable))打下基础 - 避免因继承限制导致后期重构困难

















