Callable不能直接交给Thread启动,因其call()方法有返回值且可抛出异常,而Thread构造函数只接受无返回值的Runnable;必须通过ExecutorService提交并用Future获取结果。

Java 中通过实现 Callable 接口创建线程并获取返回值,核心在于:它不能直接交给 Thread 启动,而必须配合 ExecutorService 使用,再通过 Future 对象获取执行结果。
为什么不能像 Runnable 那样直接 new Thread()?
Callable 的 call() 方法有返回值(且可抛出异常),而 Thread 的构造函数只接受 Runnable。JVM 不支持直接把 Callable 当作线程目标运行——它需要一个“适配+托管”的机制。
标准四步流程(必须按顺序)
-
定义类实现 Callable
:指定泛型类型(如 Callable<integer></integer>),重写call()方法,写具体逻辑并 return 结果 -
创建线程池:用
Executors.newFixedThreadPool(1)或其它方式获取ExecutorService -
提交任务并获得 Future:调用
executor.submit(callable)→ 返回Future<t></t> -
调用 get() 获取结果:
future.get()是阻塞方法,会等待任务完成;也可用get(timeout, unit)设超时
一个完整可运行的例子
计算 1 到 100 的和,并在主线程中拿到结果:
import java.util.concurrent.*;
class SumTask implements Callable<Integer> {
@Override
public Integer call() throws Exception {
int sum = 0;
for (int i = 1; i <= 100; i++) {
sum += i;
}
return sum; // ✅ 有返回值
}
}
public class CallableDemo {
public static void main(String[] args) throws Exception {
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<Integer> future = executor.submit(new SumTask());
System.out.println("正在计算...");
Integer result = future.get(); // ? 阻塞直到 call() 执行完
System.out.println("结果是:" + result); // 输出:5050
executor.shutdown();
}
}
注意事项和常见坑
-
Future.get()会阻塞当前线程,如果不想卡住,可先用isDone()判断,或搭配get(1, TimeUnit.SECONDS)防止无限等待 - 任务抛出的异常会在
get()时包装成ExecutionException抛出,需捕获处理 - 记得调用
executor.shutdown(),否则 JVM 可能不退出(线程池中的非守护线程还在) - 如果只是单次异步任务,用
Executors.newSingleThreadExecutor()足够;高频场景建议复用固定大小线程池


















