优先选runnable;需返回结果或处理受检异常时用callable;继承thread仅限极简演示。runnable适用于日志上报、缓存刷新等无返回场景,天然适配线程池和lambda;callable通过call()返回泛型结果并抛出exception,须配合executorservice.submit()返回future;继承thread因单继承限制、强耦合、不支持线程池而被大厂规范禁用。

绝大多数情况下,优先选 Runnable;需要返回结果或处理受检异常时,才用 Callable;直接继承 Thread 类基本不推荐,仅适合极简演示。
用 Runnable 的典型场景
适合“只管执行、不关心结果”的任务,比如日志上报、缓存刷新、异步通知、定时状态检查等。
- 任务逻辑与线程生命周期解耦,便于复用和单元测试
- 天然适配线程池(
executor.execute(runnable)),也支持 lambda 写法:() -> System.out.println("ok") - 不能抛出受检异常(如
IOException),必须在run()内部try-catch或包装成运行时异常 - 没有返回值,若硬要传结果,只能靠共享变量(如
AtomicInteger、ConcurrentHashMap),但需自行保障线程安全
用 Callable 的典型场景
当你明确需要拿到线程执行后的计算结果,或者任务本身容易抛出受检异常(如文件读取、数据库查询、HTTP 调用)时,就该用 Callable。
-
call()方法支持泛型返回值(如Callable<string></string>、Callable<integer></integer>),类型安全 - 可直接
throws Exception,不用在方法内吞异常,调用方通过Future.get()捕获原始异常(包装为ExecutionException) - 必须配合
ExecutorService.submit()使用,返回Future对象,支持超时控制(future.get(3, TimeUnit.SECONDS)) - 不能直接传给
new Thread()—— 编译会失败,因为Thread构造器只认Runnable
为什么一般不用继承 Thread 类
继承 Thread 看似直观,但实际限制多、扩展性差。
- Java 是单继承,继承了
Thread就无法再继承其他类,破坏了面向对象的灵活性 - 任务逻辑和线程管理强耦合,不利于测试、复用和资源管控
- 容易误调
thread.run()(同步执行)或重复调用start()(抛IllegalThreadStateException) - 无法直接用于线程池,也不支持 lambda,现代并发编程中已属过时做法
简单决策流程
遇到一个新任务,按顺序问自己三个问题:
- 是否需要获取执行结果?→ 否 → 选 Runnable
- 是否涉及 IO、网络或数据库操作,可能抛出
IOException、SQLException等?→ 是 → 选 Callable - 只是写个 demo 或教学示例,且确定不会扩展?→ 可临时用 Thread,但别在生产代码里出现
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











