1. Callable 的基本概念
Callable 是 Java 并发编程中的一个接口,位于 java.util.concurrent 包中。它与 Runnable 类似,但有一个重要的区别:Callable 可以返回结果,并且能够抛出异常。
接口定义
@FunctionalInterface
public interface Callable<V> {
V call() throws Exception;
}
2. Callable vs Runnable
主要区别对比
| 特性 | Runnable | Callable |
|---|---|---|
| 返回值 | void(无返回值) | 有返回值(泛型类型) |
| 异常处理 | 不能抛出受检异常 | 可以抛出受检异常 |
| 使用场景 | 简单的异步任务 | 需要返回结果的异步计算 |
| 引入版本 | Java 1.0 | Java 5.0 |
代码对比
// Runnable 示例
Runnable runnableTask = new Runnable() {
@Override
public void run() {
// 执行任务,没有返回值
System.out.println("Runnable 任务执行");
// 不能抛出受检异常,只能try-catch
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
// Callable 示例
Callable<String> callableTask = new Callable<String>() {
@Override
public String call() throws Exception {
// 执行任务,并返回结果
Thread.sleep(1000);
if (Math.random() > 0.5) {
throw new Exception("模拟异常"); // 可以抛出受检异常
}
return "Callable 任务执行结果";
}
};
3. Callable 的基本用法
使用 FutureTask 执行 Callable
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
public class CallableBasicExample {
public static void main(String[] args) throws Exception {
// 创建 Callable 任务
Callable<Integer> callable = new Callable<Integer>() {
@Override
public Integer call() throws Exception {
System.out.println("Callable 任务开始执行...");
Thread.sleep(2000); // 模拟耗时操作
int sum = 0;
for (int i = 1; i <= 100; i++) {
sum += i;
}
System.out.println("Callable 任务执行完成");
return sum; // 返回计算结果
}
};
// 使用 FutureTask 包装 Callable
FutureTask<Integer> futureTask = new FutureTask<>(callable);
// 创建线程执行任务
Thread thread = new Thread(futureTask);
thread.start();
// 主线程继续执行其他工作
System.out.println("主线程继续执行其他任务...");
// 获取任务结果(会阻塞直到任务完成)
Integer result = futureTask.get();
System.out.println("计算结果: " + result);
}
}
Lambda 表达式简化
public class CallableLambdaExample {
public static void main(String[] args) throws Exception {
// 使用 Lambda 表达式创建 Callable
Callable<String> callable = () -> {
Thread.sleep(1000);
return "Hello from Callable: " + System.currentTimeMillis();
};
FutureTask<String> futureTask = new FutureTask<>(callable);
new Thread(futureTask).start();
// 获取结果
String result = futureTask.get();
System.out.println("结果: " + result);
}
}
4. 使用线程池执行 Callable
ExecutorService 提交 Callable 任务
import java.util.concurrent.*;
public class CallableWithExecutor {
public static void main(String[] args) throws Exception {
// 创建线程池
ExecutorService executor = Executors.newFixedThreadPool(3);
// 提交多个 Callable 任务
Callable<Integer> task1 = () -> {
Thread.sleep(1000);
return 10 * 10;
};
Callable<Integer> task2 = () -> {
Thread.sleep(2000);
return 20 * 20;
};
Callable<Integer> task3 = () -> {
Thread.sleep(1500);
return 30 * 30;
};
// 提交任务并获取 Future 对象
Future<Integer> future1 = executor.submit(task1);
Future<Integer> future2 = executor.submit(task2);
Future<Integer> future3 = executor.submit(task3);
// 获取结果
System.out.println("任务1结果: " + future1.get());
System.out.println("任务2结果: " + future2.get());
System.out.println("任务3结果: " + future3.get());
// 关闭线程池
executor.shutdown();
}
}
5. 批量执行 Callable 任务
使用 invokeAll 方法
import java.util.*;
import java.util.concurrent.*;
public class CallableBatchExample {
public static void main(String[] args) throws Exception {
ExecutorService executor = Executors.newFixedThreadPool(4);
// 创建多个 Callable 任务
List<Callable<String>> tasks = new ArrayList<>();
for (int i = 1; i <= 5; i++) {
final int taskId = i;
tasks.add(() -> {
Thread.sleep(1000 * taskId);
return "任务 " + taskId + " 完成";
});
}
// 批量执行所有任务
System.out.println("开始执行所有任务...");
List<Future<String>> futures = executor.invokeAll(tasks);
// 获取所有任务结果
System.out.println("所有任务执行完成,获取结果:");
for (Future<String> future : futures) {
System.out.println(future.get());
}
executor.shutdown();
}
}
6. 异常处理
Callable 的异常处理机制
import java.util.concurrent.*;
public class CallableExceptionExample {
public static void main(String[] args) {
ExecutorService executor = Executors.newSingleThreadExecutor();
Callable<String> task = () -> {
Thread.sleep(1000);
// 模拟可能出现的异常
if (Math.random() > 0.3) {
throw new RuntimeException("任务执行失败");
}
return "任务执行成功";
};
Future<String> future = executor.submit(task);
try {
String result = future.get();
System.out.println("结果: " + result);
} catch (InterruptedException e) {
System.out.println("任务被中断: " + e.getMessage());
} catch (ExecutionException e) {
// ExecutionException 包装了 Callable 中抛出的实际异常
System.out.println("任务执行异常: " + e.getCause().getMessage());
} finally {
executor.shutdown();
}
}
}
7. 实际应用场景
场景1:并行计算
public class ParallelCalculation {
public static long calculateSum(int[] numbers, int start, int end) throws Exception {
long sum = 0;
for (int i = start; i < end; i++) {
sum += numbers[i];
// 模拟复杂计算
Thread.sleep(1);
}
return sum;
}
public static void main(String[] args) throws Exception {
int[] numbers = new int[1000];
Arrays.fill(numbers, 1);
ExecutorService executor = Executors.newFixedThreadPool(4);
// 将大任务拆分成多个小任务
List<Callable<Long>> tasks = new ArrayList<>();
int chunkSize = numbers.length / 4;
for (int i = 0; i < 4; i++) {
final int start = i * chunkSize;
final int end = (i == 3) ? numbers.length : (i + 1) * chunkSize;
tasks.add(() -> calculateSum(numbers, start, end));
}
// 并行执行
List<Future<Long>> futures = executor.invokeAll(tasks);
// 合并结果
long total = 0;
for (Future<Long> future : futures) {
total += future.get();
}
System.out.println("总和: " + total);
executor.shutdown();
}
}
场景2:超时控制
public class CallableTimeoutExample {
public static void main(String[] args) {
ExecutorService executor = Executors.newSingleThreadExecutor();
Callable<String> longRunningTask = () -> {
Thread.sleep(5000); // 模拟耗时操作
return "任务完成";
};
Future<String> future = executor.submit(longRunningTask);
try {
// 设置超时时间为2秒
String result = future.get(2, TimeUnit.SECONDS);
System.out.println("结果: " + result);
} catch (TimeoutException e) {
System.out.println("任务执行超时,取消任务");
future.cancel(true); // 尝试中断任务
} catch (Exception e) {
System.out.println("任务执行异常: " + e.getMessage());
} finally {
executor.shutdown();
}
}
}
8. 与 CompletableFuture 结合使用
import java.util.concurrent.*;
public class CallableWithCompletableFuture {
public static void main(String[] args) throws Exception {
// 使用 CompletableFuture 执行 Callable
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(1000);
return "Callable 任务结果";
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
// 异步处理结果
future.thenAccept(result -> {
System.out.println("异步处理结果: " + result);
});
// 等待任务完成
future.get();
}
}
总结
Callable 的核心特点:
-
有返回值:可以返回任意类型的结果
-
异常处理:可以抛出受检异常,通过
ExecutionException包装 -
与 Future 配合:通过
Future对象获取异步执行结果 -
线程池支持:可以通过
ExecutorService.submit()提交执行
适用场景:
-
需要返回结果的异步计算
-
并行处理大量数据
-
需要异常处理的异步任务
-
需要超时控制的长时间运行任务
最佳实践:
-
使用线程池管理 Callable 任务
-
合理处理
Future.get()的阻塞和异常 -
考虑使用
CompletableFuture进行更复杂的异步编程
1万+

被折叠的 条评论
为什么被折叠?



