假设有一个项目,有一个功能,需要异步调用一个接口,然后获取到相关的数据来进行接下来的操作
这就是之前我们说过的异步转同步操作
但是一个问题,如何保证发生请求的线程和接受请求的线程是同一个线程呢
之前的异步转同步的问题解决方案就是一个很成熟完整的实例
这就需要一个中介,去负责将消息回调回来
那么可以把上面的设计的模式总结为:
一个用于发送请求,一个接受返回请求,一个调度,用于将返回的请求进行处理
这种设计模式称为: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”来理解这个模式会更简单。