什么是Callable和Future?它们之间的关系是什么?
`Callable` 和 `Future` 是 Java 中的两个接口,它们在并发编程中扮演着重要的角色,特别是在处理异步计算时。
### Callable接口:
`Callable` 接口是 `java.util.concurrent` 包的一部分,它类似于 `Runnable` 接口,但它可以返回结果,并且可以抛出异常。`Callable` 任务通常由 `ExecutorService` 执行。
```java
public interface Callable<V> {
V call() throws Exception;
}
```
- **返回结果**:`Callable` 接口的 `call()` 方法可以返回一个泛型类型 `V` 的结果。
- **抛出异常**:与 `Runnable` 不同,`Callable` 可以抛出任何类型的检查异常(checked exceptions)。
- **用途**:适用于需要返回结果的异步任务。
### Future接口:
`Future` 接口也是 `java.util.concurrent` 包的一部分,它代表了异步计算的结果。通过 `Future` 接口,你可以查询计算是否完成,取消计算,或者等待计算结果。
```java
public interface Future<V> {
boolean cancel(boolean mayInterruptIfRunning);
boolean isCancelled();
boolean isDone();
V get() throws InterruptedException, ExecutionException;
V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;
}
```
- **查询状态**:可以查询任务是否完成(`isDone()`)、是否取消(`isCancelled()`)。
- **获取结果**:可以通过 `get()` 方法获取 `Callable` 任务的结果,如果任务还没有完成,`get()` 会阻塞直到任务完成。
- **取消任务**:如果任务还没有开始或正在运行,可以通过 `cancel()` 方法尝试取消任务。
- **超时**:`get(long timeout, TimeUnit unit)` 方法允许你指定一个超时时间,如果在超时时间内任务没有完成,将会抛出 `TimeoutException`。
### Callable和Future之间的关系:
当你将一个 `Callable` 任务提交给 `ExecutorService` 时,它会返回一个 `Future` 对象。这个 `Future` 对象代表了 `Callable` 任务的异步执行结果。具体来说:
1. **提交任务**:使用 `ExecutorService` 的 `submit(Callable<T> task)` 方法提交一个 `Callable` 任务。
2. **获取Future对象**:`submit()` 方法返回一个 `Future` 对象,该对象可以用来查询任务状态或获取任务结果。
3. **获取结果**:使用 `Future` 对象的 `get()` 方法可以获取 `Callable` 任务的返回结果。
4. **异常处理**:如果 `Callable` 任务抛出异常,`get()` 方法将会抛出 `ExecutionException`,其原因(cause)是原始异常。
5. **取消任务**:如果需要取消任务,可以使用 `Future` 对象的 `cancel()` 方法。
下面是一个简单的示例,演示如何使用 `Callable` 和 `Future`:
```java
ExecutorService executor = Executors.newSingleThreadExecutor();
Callable<Integer> task = () -> {
// 执行一些计算
return 42; // 假设这是计算结果
};
Future<Integer> future = executor.submit(task);
try {
// 获取任务结果
Integer result = future.get();
System.out.println("任务结果: " + result);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
} finally {
executor.shutdown();
}
```
在这个示例中,我们创建了一个 `Callable` 任务,提交给 `ExecutorService`,并使用返回的 `Future` 对象来获取结果。通过这种方式,`Callable` 和 `Future` 一起提供了一种强大的机制,用于处理并发环境下的异步计算和结果获取。