runnable与callable的核心差异在于返回值和异常处理:runnable的run()无返回值且不支持抛出受检异常,callable的call()支持泛型返回值和throws exception。

Runnable 和 Callable 最核心的差异就落在返回值和异常处理这两点上,不是“能不能做”,而是“设计上是否支持”。
返回值:有无决定结果能否被直接获取
Runnable 的 run() 方法返回类型是 void,执行完就结束,调用方拿不到任何结果。哪怕任务内部算出了 100,也没法传出来。
Callable 的 call() 方法声明为 V call() throws Exception,其中 V 是泛型,比如 Callable<string></string> 或 Callable<integer></integer>,意味着它天然支持返回任意类型的结果。
这个返回值不是直接拿到的,必须通过 Future.get() 获取——而这个过程是阻塞的,会等任务完成才返回值或抛出异常。
异常处理:受检异常能否向外传递
Runnable 的 run() 方法签名里没有 throws,所以它不能声明抛出受检异常(Checked Exception),比如 IOException、SQLException。如果代码里可能触发这类异常,你只能在 run() 内部用 try-catch 吞掉或转成运行时异常,否则编译不通过。
Callable 的 call() 明确允许 throws Exception,因此可以自然地把受检异常往外抛。调用方在调用 future.get() 时,会收到封装好的 ExecutionException,其 getCause() 就是原始异常,便于分类处理。
实际使用中怎么选
- 只发通知、改状态、写日志?用
Runnable—— 简单、轻量、线程池和Thread都能直接跑 - 要算个数、查个库、调个接口并带回结果?用
Callable—— 必须走ExecutorService.submit(),靠Future拿结果或捕获异常 - 想用 Lambda 写得简洁?两个都支持:
() -> {...}可作Runnable,() -> { return 42; }可作Callable<integer></integer>
小提醒:别混淆 Future 和 Callable 的关系
Future 不是 Callable 的一部分,它是任务提交后的“句柄”。Runnable 提交后也返回 Future,只是它的 get() 永远返回 null;而 Callable 返回的 Future 才真正承载了结果与异常信息。










