概念 所谓 Guarded Suspension,直译过来就是“保护性地暂停”,如果执行现在的处理会造成问题,就让执行处理的线程进行等待,这种模式通过让线程等待来保证实例的安全性。
比如,项目组团建要外出聚餐,我们提前预订了一个包间,然后兴冲冲地奔过去,到那儿后大堂经理看了一眼包间,发现服务员正在收拾,就会告诉我们:“您预订的包间服务员正在收拾,请您稍等片刻。”过了一会,大堂经理发现包间已经收拾完了,于是马上带我们去包间就餐。
结构图 下图就是 Guarded Suspension 模式的结构图,非常简单,一个对象 GuardedObject ,内部有一个成员变量——受保护的对象,以及两个成员方法 —— get(Predicate p) 和 onChanged(T obj) 方法。
![Guarded Suspension模式结构图](/images/java/Guarded Suspension模式结构图.png)
其中,对象 GuardedObject 就是我们前面提到的大堂经理,受保护对象就是餐厅里面的包间;受保护对象的 get() 方法对应的是我们的就餐,就餐的前提条件是包间已经收拾好了,参数 p 就是用来描述这个前提条件的;受保护对象的 onChanged() 方法对应的是服务员把包间收拾好了,通过 onChanged() 方法可以 fire 一个事件,而这个事件往往能改变前提条件 p 的计算结果。下图中,左侧的绿色线程就是需要就餐的顾客,而右侧的蓝色线程就是收拾包间的服务员。
模板代码 GuardedObject 的内部实现非常简单,是管程的一个经典用法,核心是:get() 方法通过条件变量的 await() 方法实现等待,onChanged() 方法通过条件变量的 signalAll() 方法实现唤醒功能。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 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 { 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 模式本质上是一种等待唤醒机制的实现,只不过 Guarded Suspension 模式将其规范化了。规范化的好处是你无需重头思考如何实现,也无需担心实现程序的可理解性问题,同时也能避免一不小心写出个 Bug 来。但 Guarded Suspension 模式在解决实际问题的时候,往往还是需要扩展的。下面以Web请求异步响应 为例演示如何扩展。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 class GuardedObject <T > { T obj; final Lock lock = new ReentrantLock(); final Condition done = lock.newCondition(); final int timeout = 2 ; final static Map<Object, GuardedObject> gos = new ConcurrentHashMap<>(); 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 { 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(); } } } Respond handleWebReq () { int id = 序号⽣成器.get(); Message msg1 = new Message(id, "{...}" ); GuardedObject<Message> go = GuardedObject.create(id); send(msg1); Message r = go.get(t->t != null ); } void onMessage (Message msg) { GuardedObject.fireEvent(msg.id, msg); }