推荐实现runnable接口而非继承thread类,因后者受单继承限制、扩展性差且易混淆start()与run();runnable解耦任务与执行环境,支持lambda、复用、线程池及资源共享。

Java 中创建基础线程最常用的是继承 Thread 类和实现 Runnable 接口两种方式,但“正确”不只看能否运行,更在于是否符合设计原则、可维护性与实际场景适配。下面从写法、关键细节和典型误区三方面说清楚。
继承 Thread 类的写法与注意点
本质是把“任务逻辑”直接塞进线程对象里,适合简单、独立、无需复用的任务。
- 定义子类继承
Thread,重写run()方法,里面放要并发执行的代码 - 不要直接调用
run()—— 这只是普通方法调用,不会启动新线程;必须调用start() - 每个线程都需要 new 一个子类实例,资源(如实例变量)默认不共享,彼此隔离
- 由于 Java 单继承限制,该类不能再继承其他类,扩展能力受限
实现 Runnable 接口的写法与优势
把“做什么”(任务)和“谁来做”(线程)分开,更贴近真实业务逻辑,是推荐的主流做法。
- 定义类实现
Runnable接口,重写run()方法,封装任务逻辑 - 用这个实例作为参数传给
Thread构造器:new Thread(runnable, "名称") - 多个
Thread可共用同一个Runnable实例,天然支持资源共享(比如共享票数、计数器) - 类仍可继承其他父类,也能实现多个接口,灵活性高
两种方式在运行效果上的直观差异
同样模拟卖 5 张票,对比输出就能看出区别:
- 继承
Thread:三个线程各卖自己的 5 张票,共卖出 15 张,count是每个对象的私有字段 - 实现
Runnable:三个线程争抢同一份票源,count是共享字段,最终只卖出 5 张(需加synchronized防止超卖)
为什么 Runnable 更值得优先选用
不是语法难易问题,而是工程合理性:
-
Thread类本身已经实现了Runnable,说明它本质上也是个“执行者代理”,任务本就不该和线程强绑定 - 后续想接入线程池、使用
ExecutorService、配合 Lambda 表达式,都要求传入Runnable或Callable - 面向接口编程让测试、替换、复用更容易——任务逻辑可以脱离线程环境单独单元测试
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











