当前位置: 首页 > news >正文

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

相关文章:

  • C语言 ——— 认识C语言
  • 应对海量数据归档难题?AWS Glacier 的低成本冷存储解决方案实践指南
  • Keras使用1
  • 【AI学习从零至壹】语⾔模型及词向量相关知识
  • linux多线(进)程编程——(6)共享内存
  • 链表代码实现(C++)
  • C语言--常见的编程示例
  • 医药采购系统平台第5天01:药品目录导入功能的实现Oracle触发器的定义供货商药品目录模块的分析供货商目录表和供货商控制表的分析、数据模型设计和优化
  • Rasa 模拟实现超简易医生助手(适合初学练手)
  • Tkinter表格与列表框应用
  • 制作像素风《饥荒》类游戏的整体蓝图和流程
  • ubuntu 2404 安装 vcs 2018
  • Doris 安装部署、实际应用及优化实践:对比 ClickHouse 的深度解析
  • 从零搭建高可用Kafka集群与EFAK监控平台:全流程实战总结
  • Foxmail邮件客户端跨站脚本攻击漏洞(CNVD-2025-06036)技术分析
  • Go:基本数据
  • leetcode 139. Word Break
  • < 自用文 Project-30.6 Crawl4AI > 为AI模型优化的网络爬虫工具 帮助收集和处理网络数据的工具
  • Java中的数组
  • 苍穹外卖Day-5
  • 建设银行南昌分行引金融“活水”,精准灌溉乡村沃土
  • 中国海油总裁:低油价短期影响利润,但也催生资产并购机会
  • 直播电商行业代表呼吁:携手并肩伸出援手助力外贸企业攻坚克难
  • 新任浙江省委常委、杭州市委书记刘非开展循迹溯源学习调研
  • 上海市市管干部任职前公示:赵亮拟为地区区长人选
  • 商务部:入境消费增长潜力巨大,离境退税有助降低境外旅客购物成本