面试题答案
一键面试1. 获取结果方式的不同
- Future:
Future
获取异步任务执行结果主要通过get()
方法。这个方法是阻塞的,即调用线程会一直等待,直到异步任务完成并返回结果。如果异步任务抛出异常,get()
方法会将异常重新抛出。另外,Future
还有get(long timeout, TimeUnit unit)
方法,允许设置等待的超时时间,若超时任务仍未完成,会抛出TimeoutException
。- 它缺乏对异步任务完成后的链式处理能力,通常需要手动轮询
isDone()
方法来判断任务是否完成,以避免长时间阻塞。
- CompletableFuture:
CompletableFuture
获取结果除了get()
和get(long timeout, TimeUnit unit)
(与Future
类似的阻塞方法)外,还提供了丰富的非阻塞方式。- 可以通过
thenApply
、thenAccept
、thenRun
等方法在异步任务完成后进行链式处理。thenApply
用于将前一个异步任务的结果作为参数,进行转换并返回新的结果;thenAccept
用于消费前一个异步任务的结果,但不返回新结果;thenRun
则在异步任务完成后执行一段无参的代码块。 CompletableFuture
还支持多个异步任务的组合操作,如allOf
(等待所有任务完成)和anyOf
(只要有一个任务完成)。
2. 示例说明
Future示例
import java.util.concurrent.*;
public class FutureExample {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService executorService = Executors.newSingleThreadExecutor();
Future<Integer> future = executorService.submit(() -> {
// 模拟耗时操作
Thread.sleep(2000);
return 42;
});
try {
System.out.println("等待任务完成...");
Integer result = future.get(); // 阻塞等待任务完成
System.out.println("任务结果: " + result);
} catch (TimeoutException e) {
System.out.println("任务执行超时");
} finally {
executorService.shutdown();
}
}
}
CompletableFuture示例
import java.util.concurrent.*;
public class CompletableFutureExample {
public static void main(String[] args) {
CompletableFuture.supplyAsync(() -> {
// 模拟耗时操作
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return 42;
}).thenApply(result -> {
System.out.println("接收到结果: " + result);
return result * 2;
}).thenAccept(finalResult -> {
System.out.println("最终结果: " + finalResult);
});
// 主线程防止退出
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
在Future
示例中,get()
方法阻塞主线程直到任务完成。而在CompletableFuture
示例中,通过链式调用的方式,在任务完成后可以非阻塞地对结果进行处理,增强了异步编程的灵活性和可读性。