一、Callable 接口定义
@FunctionalInterface
public interface Callable<V> {
V call() throws Exception; // 返回类型为泛型V,可抛出异常
}
二、基本使用步骤
1. 定义 Callable 任务
// 示例1:计算两个数的和
Callable<Integer> sumTask = new Callable<>() {
@Override
public Integer call() throws Exception {
return 1 + 2;
}
};
// 示例2:Lambda简化写法(推荐)
Callable<Integer> sumTask = () -> 1 + 2;
2. 提交任务到线程池
// 创建线程池
ExecutorService executor = Executors.newFixedThreadPool(2);
// 提交任务,返回Future对象
Future<Integer> future = executor.submit(sumTask);
3. 通过 Future 获取结果
try {
Integer result = future.get(); // 阻塞直到任务完成
System.out.println("结果:" + result); // 输出:3
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
} finally {
executor.shutdown(); // 关闭线程池
}
三、Future 核心方法详解
方法 | 作用 |
---|---|
V get() | 阻塞等待任务完成,返回结果。 |
V get(long timeout, TimeUnit unit) | 阻塞最多指定时间,超时抛出 TimeoutException 。 |
boolean isDone() | 检查任务是否完成(包括正常结束、异常终止或取消)。 |
boolean cancel(boolean mayInterrupt) | 尝试取消任务:若任务未开始,直接取消;若运行中,mayInterrupt=true 会尝试中断。 |
示例:设置超时和取消任务
Future<Integer> future = executor.submit(() -> {
Thread.sleep(3000); // 模拟耗时操作
return 100;
});
try {
Integer result = future.get(1, TimeUnit.SECONDS); // 等待1秒
} catch (TimeoutException e) {
System.out.println("任务超时");
future.cancel(true); // 中断任务
}
四、处理异常
Callable
抛出的异常会被封装到 ExecutionException
中,需通过 getCause()
获取原始异常:
Callable<Integer> errorTask = () -> {
throw new IOException("模拟IO异常");
};
Future<Integer> future = executor.submit(errorTask);
try {
future.get();
} catch (ExecutionException e) {
Throwable cause = e.getCause();
if (cause instanceof IOException) {
System.err.println("捕获到IO异常: " + cause.getMessage());
}
}
五、批量提交任务
1. invokeAll:提交多个任务,统一获取结果
List<Callable<Integer>> tasks = Arrays.asList(
() -> 1 + 1,
() -> 2 + 2,
() -> 3 + 3
);
List<Future<Integer>> futures = executor.invokeAll(tasks);
for (Future<Integer> f : futures) {
System.out.println(f.get()); // 输出:2, 4, 6
}
2. invokeAny:提交多个任务,返回第一个完成的结果
Integer result = executor.invokeAny(Arrays.asList(
() -> { Thread.sleep(2000); return 10; },
() -> { Thread.sleep(1000); return 20; } // 该任务更快完成
));
System.out.println(result); // 输出:20
六、使用 FutureTask 直接启动任务
FutureTask
实现了 Runnable
和 Future
,可直接通过 Thread
或线程池执行:
Callable<Integer> task = () -> 5 * 5;
FutureTask<Integer> futureTask = new FutureTask<>(task);
// 方式1:通过Thread启动
new Thread(futureTask).start();
System.out.println(futureTask.get()); // 输出:25
// 方式2:提交到线程池
executor.submit(futureTask);
七、线程池管理注意事项
-
关闭线程池
使用shutdown()
或shutdownNow()
避免资源泄漏:executor.shutdown(); // 等待所有任务完成 // executor.shutdownNow(); // 立即终止所有任务
-
选择线程池类型
newCachedThreadPool
:适合短任务,自动回收空闲线程。newFixedThreadPool
:固定线程数,适合长期任务。newScheduledThreadPool
:支持定时任务。
八、高级用法
1. 结合 Lambda 表达式简化代码
executor.submit((Callable<String>) () -> "Hello, Callable");
2. 使用 CompletableFuture(JDK 8+)
将 Callable
转换为 CompletableFuture
实现链式调用:
CompletableFuture.supplyAsync(() -> {
// 模拟计算
return 100;
}, executor).thenAccept(result -> {
System.out.println("结果:" + result);
});
九、完整代码示例
import java.util.concurrent.*;
public class CallableDemo {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(2);
// 提交任务
Future<Integer> future = executor.submit(() -> {
Thread.sleep(1000);
return 1 + 2;
});
try {
// 设置超时并获取结果
Integer result = future.get(2, TimeUnit.SECONDS);
System.out.println("结果:" + result);
} catch (TimeoutException e) {
System.err.println("任务超时");
} catch (ExecutionException e) {
System.err.println("任务异常:" + e.getCause());
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
executor.shutdown();
}
}
}