假设有一个项目,有一个功能,需要异步调用一个接口,然后获取到相关的数据来进行接下来的操作

这就是之前我们说过的异步转同步操作

图片

但是一个问题,如何保证发生请求的线程和接受请求的线程是同一个线程呢

之前的异步转同步的问题解决方案就是一个很成熟完整的实例

这就需要一个中介,去负责将消息回调回来

那么可以把上面的设计的模式总结为:

一个用于发送请求,一个接受返回请求,一个调度,用于将返回的请求进行处理

这种设计模式称为:Guarded Suspension模式

整体设计如下

图片

简单来说里面拥有两个方法,一个get方法,一个onChange方法

get方法中通过await方法进行等待,onChanged()通过singalAll()来实现唤醒功能

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();

}

}

}

在这个模式中拥有两个核心方法,一个get()方法,一个onChange()方法,调用get()实现等待,onChange()实现唤醒

但是如何确定,发送请求的线程和接受的线程是同一个线程呢,这就要一个引路人,或者说一个协调者来帮忙这个

那可以考虑使用一个Map来进行协调,Key是一个id,Value是对应的对象

并且新增加两个方法,每一个是create(),fireEvent()

create()方法用于创建一个实例并且将这个实例放在Map中,

fireEvent()用于寻找对应接受的实例

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);

}

}

//获取受保护对象

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();

}

}

}

这个设计模式本质上来说是一个等待唤醒机制的实现,在Dubbo中也有所涉猎.

Guarded Suspension 模式也常被称作 Guarded Wait 模式、Spin Lock 模式(因为使用了 while 循环去等待),这些名字都很形象,不过它还有一个更形象的非官方名字:多线程版本的 if。单线程场景中,if 语句是不需要等待的,因为在只有一个线程的条件下,如果这个线程被阻塞,那就没有其他活动线程了,这意味着 if 判断条件的结果也不会发生变化了。但是多线程场景中,等待就变得有意义了,这种场景下,if 判断条件的结果是可能发生变化的。所以,用“多线程版本的 if”来理解这个模式会更简单。

发表评论

邮箱地址不会被公开。 必填项已用*标注