java中的Future的设计模式 手写一个简易的Future
案例
例如:今天是小妹的生日,需要一个蛋糕有点仪式感,于是去蛋糕店预定,预定完之后,店老板说蛋糕做好了,到时电话通知你,不可能在这傻傻的等着吧,还有其他事情要做啊,于是我的去做其他事情,等老板电话后再来取蛋糕。这样可以充分利用自己的时间去赚钱,如果用这个案例写一个Java代码 如何实现,
Future的理解和用途
Future是个未来的事情,相当与一个票据,或者可以理解是一个凭证,用这个凭证去获取所需要的结果,
代码的逻辑解析
SimpleFuture —>代表未来的一个凭据
SimpleFutureTask —>将你的调用逻辑进行隔离封装
SimpleFutureService —> 桥接Future和FutureTask
这是一种很好的设计模式 SimpleFuture 不需要知道 SimpleFutureTask的存在,而SimpleFutureTask也不需要知道SimpleFuture 的存在,只要SimpleFutureService 需要知道他们两者的存在,而对于调用者而言,只要知道SimpleFutureService 就行,我们将业务逻辑封装成一个task模式,并且返回一个SimpleFuture
简单的Future凭证接口
1、get方法
获取任务结束后返回的结果,如果调用时,任务还没有结束,则会进行阻塞线程,直到任务完成。该阻塞是可以被打断的,打断的线程是调用get方法的线程,被打断后原任务会依旧继续执行。
/**
* SimpleFuture接口定义了一个简单的异步计算的结果获取方法
* 它提供了一种机制来获取异步任务的结果,如果任务尚未完成,则调用get方法的线程会被阻塞,
* 直到计算完成并且结果可用
*
* @param <T> 表示异步计算结果的类型
*/
public interface SimpleFuture<T> {
/**
* 获取异步计算的结果如果计算尚未完成,则此方法会阻塞,直到计算完成
* 如果计算过程中遇到中断,此方法会抛出InterruptedException
*
* @return 异步计算的结果
* @throws InterruptedException 如果调用get方法的线程在等待计算完成时被中断
*/
T get() throws InterruptedException;
}
获取任务的结果
/**
* SimpleFutureTask接口定义了一个异步任务的标准.
* 它代表了一个将会在将来执行的任务,并且该任务有一个结果.
* 这个接口的主要用途是为那些想要实现异步执行并返回结果的任务提供一个统一的标准.
*
* @param <T> 表示任务返回结果的类型.
*/
public interface SimpleFutureTask<T> {
/**
* 执行异步任务并返回结果.
* 该方法将在某个时刻被调用,以期望异步地完成任务并返回结果.
*
* @return 任务的结果,类型为泛型T.
*/
T call();
}
实现SimpleFuture的接口
/**
* AsynSimpleFuture 类实现了一个异步操作的简单未来对象
* 它允许在一个线程中设置结果,在另一个线程中获取结果
* 主要用于线程间通信,以异步方式处理任务的结果
*
* @param <T> 未来操作结果的类型
*/
public class AsynSimpleFuture<T> implements SimpleFuture<T>{
// 标记任务是否完成,volatile 关键字确保多线程环境下的可见性
private volatile boolean finished = false;
// 存储任务的结果
private T result;
/**
* 当任务完成时调用此方法,它会设置结果值并通知所有等待的线程
*
* @param result 任务的结果
*/
public void finish(T result){
synchronized (this){
this.result = result;
this.finished = true;
this.notifyAll();
}
}
/**
* 获取任务的结果如果任务未完成,当前线程会等待直到任务完成
*
* @return 任务的结果
* @throws InterruptedException 如果在等待过程中线程被中断
*/
@Override
public T get() throws InterruptedException {
synchronized (this){
while (!finished){
this.wait();
}
}
return result;
}
}
将SimpleFutureTask和 SimpleFutureTask 或 AsynSimpleFuture联系起来
/**
* SimpleFutureService类提供了异步执行任务的功能
* 它通过管理线程来执行提交的任务,并返回一个表示异步计算结果的AsynSimpleFuture对象
*/
public class SimpleFutureService {
/**
* 提交一个SimpleFutureTask任务进行异步执行
* 该方法的返回值可以为 SimpleFuture<T>
* @param task 要异步执行的任务,它实现了call方法来定义任务的具体执行逻辑
* @return 返回一个AsynSimpleFuture对象,通过它可以获取任务执行结果
*
* 此方法创建并启动一个新的线程来执行给定的任务任务的执行结果会被封装在这个AsynSimpleFuture对象中
* 使用者可以使用这个对象来获取任务执行结果,而无需阻塞当前线程
*/
public <T> AsynSimpleFuture<T> submit(SimpleFutureTask<T> task, Consumer<T> consumer) {
AsynSimpleFuture<T> future = new AsynSimpleFuture<>();
new Thread(() -> {
T result = task.call();
future.finish(result);
consumer.accept(result);
}).start();
return future;
}
}
测试一下代码的效果
/**
* SyncInvoker 类用于演示如何使用 SimpleFutureService 来执行异步任务并在任务完成后获取结果
*/
public class SyncInvoker {
/**
* 主函数执行异步任务并展示执行结果
* @param args 命令行参数
* @throws InterruptedException 如果在睡眠期间线程被中断
*/
public static void main(String[] args) throws InterruptedException {
// 创建 SimpleFutureService 实例
SimpleFutureService simpleFutureService = new SimpleFutureService();
// 提交异步任务并获取未来结果
simpleFutureService.submit(SyncInvoker::bookAndPickUpCake,System.out::println);
Optional.of("-----*************-------").ifPresent(System.out::println);
// 应该是在获取结果之前,先执行其他任务
Optional.of("-----go to work-------").ifPresent(System.out::println);
// 模拟其他任务的耗时
Thread.sleep(5000);
Optional.of("-----I finish my work -------").ifPresent(System.out::println);
Optional.of("-----####去蛋糕店等待或等待老板电话或老板送货上面#####-------").ifPresent(System.out::println);
}
/**
* 模拟一个耗时的异步任务,例如预订并取回蛋糕
* @return 任务结果,在这个例子中是蛋糕的名称
*/
private static String bookAndPickUpCake() {
try {
// 模拟耗时操作
Thread.sleep(10000);
return "BIRTHDAY CAKE";
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
执行的结果:
-----*************-------
-----go to work-------
-----I finish my work -------
-----####等待老板电话或老板送货上面#####-------
BIRTHDAY CAKE