线程阻塞场景
- 任务未完成时调用
get
:当CompletableFuture
所代表的异步任务尚未完成,此时调用get
方法,调用线程会一直阻塞,直到任务完成。例如,在一个复杂的计算任务,或者需要远程调用且网络延迟较大的任务场景下,任务执行时间较长,如果在任务未结束时就调用get
,就会发生阻塞。
- 任务执行过程中出现异常:若
CompletableFuture
在执行任务过程中抛出异常,调用get
方法获取结果时,线程也会阻塞,直到异常被处理。异常处理机制会使get
方法等待,直到明确异常情况并处理完成。
代码模拟
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
public class CompletableFutureExample {
public static void main(String[] args) {
// 模拟任务未完成时调用get
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(5000); // 模拟长时间运行的任务
} catch (InterruptedException e) {
e.printStackTrace();
}
return "Task 1 completed";
});
try {
System.out.println("Before get, trying to get result: " + future1.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
// 模拟任务执行过程中出现异常
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
throw new RuntimeException("Task 2 error");
});
try {
System.out.println("Before get, trying to get result: " + future2.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
避免性能问题
- 使用异步回调:通过
thenApply
、thenAccept
、thenRun
等方法注册回调函数,这些回调会在任务完成时异步执行,不会阻塞主线程。
CompletableFuture.supplyAsync(() -> "Hello")
.thenApply(s -> s + ", World")
.thenAccept(System.out::println);
- 设置超时:使用
get(long timeout, TimeUnit unit)
方法设置获取结果的超时时间,避免无限期阻塞。
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "Task completed";
});
try {
String result = future.get(2, TimeUnit.SECONDS);
System.out.println(result);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
e.printStackTrace();
}
- 结合
CompletableFuture
的组合操作:利用allOf
、anyOf
等方法处理多个CompletableFuture
,合理安排任务执行和结果获取逻辑,减少阻塞时间。
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Result 1");
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "Result 2");
CompletableFuture<Void> combinedFuture = CompletableFuture.allOf(future1, future2);
combinedFuture.thenRun(() -> {
try {
System.out.println("Future 1 result: " + future1.get());
System.out.println("Future 2 result: " + future2.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}).join();