runnable 定义任务逻辑,thread 负责执行——两者解耦;应使用具名类实现 runnable(如 sendemailtask),不继承 thread、不创建线程,便于测试与复用;thread 显式传入该实例并命名,支持多线程、线程池、定时调度及直接调用 run()。

关键在于:Runnable 只定义“做什么”,Thread 只负责“谁来跑”——两者不耦合、不混写、不互相依赖。传入具名 Runnable(即明确命名的类或变量)是实现这种分离最清晰、最可控的方式。
用具名类实现 Runnable,职责一目了然
定义一个独立的、有业务含义的类(比如 SendEmailTask、CacheRefreshJob),只实现 run() 方法,不继承 Thread,也不创建线程。
- 这个类可被单元测试直接调用
task.run(),无需启动线程 - 它不持有
Thread.currentThread()或interrupt()等线程生命周期逻辑 - 类名本身就能表达意图,比匿名内部类或 lambda 更易维护和复用
构造 Thread 时显式传入,切断隐式绑定
不要在 Runnable 实现类里 new Thread(),也不要让 Runnable 自己 start();而是由外部按需创建 Thread 并注入任务:
new Thread(new SendEmailTask(), "email-sender-1").start();new Thread(new CacheRefreshJob(), "cache-refresher").start();- 线程名(第二个参数)可读性强,便于排查日志和监控
同一 Runnable 实例可被多处调度,真正复用
一个具名 Runnable 对象不是一次性的。只要它无状态或线程安全,就能被反复使用:
- 传给多个 Thread:
Thread t1 = new Thread(task); Thread t2 = new Thread(task); t1.start(); t2.start(); - 传给线程池:
executor.submit(task);(注意返回 Future>,无结果) - 传给定时器:
scheduleAtFixedRate(task, 0, 30, SECONDS); - 甚至调试时直接
task.run()—— 它只是个普通对象,没有“必须跑在线程上”的强制约束
警惕隐式线程依赖,守住解耦边界
即使用了具名 Runnable,仍可能无意中破坏分离原则:
- 避免在 run() 中调用
Thread.sleep()或wait()以外的线程控制方法(如Thread.interrupted()应由执行器判断) - 慎用
ThreadLocal:它的值绑定到当前执行线程,一旦任务被不同线程复用,行为不可控 - 若任务需中断响应,应在 run() 内定期检查
Thread.currentThread().isInterrupted(),而不是依赖 Runnable 自身管理中断状态










