Thread和Runnable无返回值,仅能通过共享变量间接传递结果且异常无法抛出;Callable支持泛型返回值和受检异常,需配合ExecutorService和Future获取结果。

创建线程时,Thread、Runnable 和 Callable 的核心差异之一,就在于任务执行后能否获取结果——也就是变量返回能力。这直接影响你是否能拿到计算值、处理异常或做后续逻辑判断。
Thread 与 Runnable:均无返回值
两者都只定义了 void run() 方法,执行完就结束,不提供任何返回机制。
- Thread 是类,通过继承重写
run();Runnable 是接口,通过实现run(),再传给 Thread 构造器启动 - 即使你在
run()内部计算出一个 int 或 String,也无法直接传出来;若想“带回结果”,只能靠外部共享变量(如 static 字段、AtomicInteger、或传入的容器对象),但这种方式不安全、不可靠,也缺乏同步保障 - 异常只能在
run()内部捕获并处理,无法向上抛出——比如InterruptedException必须自己catch,调用方完全不知情
Callable:唯一支持类型化返回值的方案
Callable 的 call() 方法声明为 V call() throws Exception,天然支持泛型返回值和受检异常。
- 返回值通过
Future.get()获取,例如Future或Future,类型安全且延迟可控 - 必须配合
ExecutorService.submit()使用(推荐),才能获得Future实例;单独用new Thread(new FutureTask(...))虽可行,但绕过了线程池管理、超时控制、批量提交等关键能力 - 异常不会丢失:
Future.get()会把call()中抛出的异常包装成ExecutionException,调用方可以明确捕获并区分原始异常类型
实际选型建议
要不要返回值,决定了该用哪一种:
- 仅需“执行一段逻辑”(如日志上报、缓存刷新、异步通知)→ 用
Runnable最轻量,耦合低,推荐 - 需要明确知道执行结果(如远程调用响应、计算总和、生成 token)→ 必须用
Callable+ExecutorService - 继承
Thread类一般不推荐,它破坏了面向接口的设计原则,且无法复用其他父类,仅适合极简 demo 或教学场景










