知识点:异步结果、异步回调、Supplier、CompletableFuture 等。
关于任务异步执行,两个点不可避免:异步结果和异步回调。而在我的工程中有这样一段代码:
使用 CompletableFuture 进行封装,可以异步执行,异步回调,通过 get() 等待异步任务的结果。
注:任何方法都可以封装成 CallbackTask 调用。
public static <R> Optional<R> invokeWithResult(CallbackTask<R> executeTask) throws Exception {
CompletableFuture<R> invoke = CompletableFuture.supplyAsync(() -> {
// 异步执行
return executeTask.execute();
}).whenComplete((result, throwable) -> {
// 执行结束后处理
executeTask.onSuccess(result);
}).exceptionally(throwable -> {
// 失败时候处理
executeTask.onFailure(throwable);
return null;
});
// 获取异步调用结果
return Optional.ofNullable(invoke.get(DEFAULT_MAX_TIMEOUT, TimeUnit.SECONDS));
}
但用着用着就发现明显的不对劲,主线程会阻塞等待结果。异步转同步!
Optional.ofNullable(invoke.get(DEFAULT_MAX_TIMEOUT, TimeUnit.SECONDS))。get() 方法会进行阻塞等待。invokeWithResult 封装得不是很理想。
/**
* Waits if necessary for this future to complete, and then
* returns its result. (简言之:阻塞等待结果)
*/
public T get() throws InterruptedException, ExecutionException {
Object r;
return reportGet((r = result) == null ? waitingGet(true) : r);
}
有没有好的方法,不执行阻塞等待呢?
直接返回 CompletableFuture 就可以了,等主线程用到的时候,再调用 CompletableFuture#get获取。
但用 CompletableFuture 作为方法返回值,个人觉得语义并不很好,有没有其他方式呢,带着这个问题过了一天,终于有了灵感 -- supplier 惰性求值。
Supplier接口在 Java 中通常被用于实现惰性求值。Supplier的特点在于它的 get()方法,该方法没有输入参数,并在被调用时返回一个T类型的值。在Supplier 被定义时,并不会执行 get() 方法中的代码;只有在显式调用 get() 方法时,代码才会执行,并且生成并提供一个值。
@FunctionalInterface
public interface Supplier<T> {
/**
* Gets a result.
*
* @return a result
*/
T get();
}
这允许代码在需要时才生成值,从而实现了惰性求值。
因为Supplier推迟了执行,直到调用者准备好接收值,这可以提高性能,避免不必要的计算,尤其是在处理耗时的操作或创建资源密集型对象时。