Guarded Suspension模式

本文介绍了GuardedSuspension模式如何确保在服务A与服务B通过MQ异步交互时,A能够可靠接收B的响应结果。通过实例演示了如何使用受保护对象、条件变量和等待唤醒机制,以及如何扩展模式以管理消息与结果的对应关系。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Guarded Suspension 模式

考虑一个场景,当两个服务通过MQ进行交互时,服务A生产消息,服务B消费消息,两者为异步操作,我们如何来保证A消费到B返回的结果呢?

在这里插入图片描述

Guarded Suspension模式

所谓 Guarded Suspension,直译过来就是“保护性地暂停”。

Guarded Suspension模式的结构图如下,其中包含:

  • 一个受保护的对象GuardedObject
  • 两个成员方法:get(Predicate p)onChanged(T obj)方法

在这里插入图片描述

GuardedObject 是管程的一个经典用法,将等待-通知机制展现得淋漓尽致。我们只需要检查条件变量的状态,来判断“受保护对象”是否能被访问即可。

核心实现:

  • get(Predicate p) 通过条件变量的await()实现等待
  • onChanged() 通过条件变量的signalAll()实现唤醒功能
class GuardedObject<T> {
    // 受保护的对象
    T obj;
    final Lock lock = new ReentrantLock();
    final Condition done = lock.newCondition();
    final int timeout = 1;
    
    // 获取受保护对象
    T get(Predicate<T> p) {
        lock.lock();
        try {
            //MESA管程推荐写法
            while(!p.test(obj)) {
                done.await(timeout,
                    TimeUnit.SECONDS);
            }
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            lock.unlock();
        }
        // 返回非空的受保护对象
        return obj;
    }
    
    // 事件通知方法
    void onChanged(T obj) {
        lock.lock();
        try {
            this.obj = obj;
            done.signalAll();
        } finally {
            lock.unlock();
        }
    }
}
扩展Guarded Suspension模式

我们来模拟消息消费场景,

    //处理浏览器发来的请求
    Respond handleWebReq() {
        // 创建一消息
        Message msg = new
            Message("1", "{...}");
        // 发送消息
        send(msg);
        //利用GuardedObject实现等待
        GuardedObject<Message> go
            =new GuardObjec<>();
        Message r = go.get(
            t->t != null);
    }
    
    void onMessage(Message msg) {
        //如何找到匹配的go
        GuardedObject<Message> go =  
        go.onChanged(msg);
    }

服务A处理web请求,向MQ发送消息,等待消息反馈结果;服务B消费消息,向MQ反馈结果。

那么服务B消费消息后,如何通知服务A呢?我们需要找到Message对应的GuardedObject对象。

这里我们在GuardedObject中维护一个Map,用以映射消息和受保护对象的关系。

class GuardedObject<T> {
    // 受保护的对象
    T obj;
    final Lock lock = new ReentrantLock();
    final Condition done = lock.newCondition();
    final int timeout = 2;
    //保存所有GuardedObject
    final static Map<Object, GuardedObject> gos = new ConcurrentHashMap<>();
    //静态方法创建GuardedObject
    static <K> GuardedObject create(K key) {
        GuardedObject go = new GuardedObject();
        gos.put(key, go);
        return go;
    }
    
    // 消费
    static <K, T> void fireEvent(K key, T obj){
        GuardedObject go = gos.remove(key);
        if (go != null) {
            go.onChanged(obj);
        }
    }

    // 事件通知方法
    void onChanged(T obj) {
        lock.lock();
        try {
            this.obj = obj;
            done.signalAll();
        } finally {
            lock.unlock();
        }
    }
    
    // 获取受保护对象
    T get(Predicate<T> p) {
        lock.lock();
        try {
            //MESA管程推荐写法
            while(!p.test(obj)){
                done.await(timeout,
                    TimeUnit.SECONDS);
            }
        } catch(InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            lock.unlock();
        }
        //返回非空的受保护对象
        return obj;
    }
}
  • create 创建 GuardedObject,并统一管理
  • fireEvent 触发消费,改变条件变量状态
  • get 获取消费结果

Guarded Suspension 模式本质上是一种等待唤醒机制的实现,只不过Guarded Suspension 模式将其规范化,通常我们会根据实际场景扩展使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值