实现runnable接口将任务逻辑与执行者分离,任务只专注业务代码且不管理线程生命周期,执行者(如thread、线程池)仅负责调度,支持复用、组合与测试,但需自行处理线程安全与threadlocal依赖。

实现 Runnable 接口,本质是把“做什么”和“谁来做”分开——任务逻辑不再绑定具体线程对象,而是以纯行为单元存在,可被任意执行者调度。
任务只管逻辑,不碰线程生命周期
实现类只需专注写 run() 方法里的业务代码:读文件、处理订单、调用 API……它不创建线程、不调用 start()、也不感知自己是否在运行或已被中断。比如一个日志写入任务:
- 只做“格式化日志 + 写入磁盘”,不 new Thread,不 sleep 主动让出时间片
- 有状态时(如共享计数器),需自行加锁或用原子类,Runnable 本身不提供线程安全保证
- 单元测试时直接
task.run()就能验证逻辑,无需启动真实线程
执行者只管调度,不掺杂业务细节
Thread 或线程池等执行实体,只负责资源分配与触发执行,完全不理解任务内容:
-
new Thread(task).start():JVM 创建新 OS 线程,回调 run() -
executor.submit(task):任务进队列,由池中空闲线程执行 -
SwingUtilities.invokeLater(task):交由事件调度线程异步执行
同一份任务代码,换执行方式只需改一行,业务逻辑零改动。
支持复用与组合,避开继承限制
Runnable 是接口,不是父类,因此:
- 一个实例可被多个 Thread 同时执行(注意状态竞争)
- 可同时实现
Serializable、Comparable等其他接口 - 不占用类的唯一继承名额,还能继续继承业务基类
- Lambda 写法简洁:
() -> System.out.println("done"),但无法抛受检异常,需包装为 RuntimeException
关键操作别踩坑
几个高频误点要盯住:
- ❌
new Thread(task).run()—— 这只是普通方法调用,仍在当前线程同步执行,毫无并发 - ✅ 必须用
.start()才触发 JVM 创建新线程并回调 run() - ⚠️ 线程池 submit(Runnable) 返回的是
Future>,get() 永远返回 null;取消任务需配合Thread.interrupted()检查 - ⚠️ 若任务隐式依赖
ThreadLocal(如用户上下文),切换执行者后可能丢失,得显式传递或重置











