从Exchager数据交换到基于trade-off的系统设计

可以使用JDK提供的Exchager类进行同步交换:进行数据交换的双方将互相等待对方,直到双方的数据都准备完毕,才进行交换。Exchager类很少用到,但理解数据交换的时机却十分重要,这是一个基于trade-off的系统设计。下述分析方法能扩展到诸多系统设计的场景中,帮助我们更好的进行trade-off。

《Java并发编程实战》中介绍了判定数据交换时机的两种方案,却不甚清晰。从“时机选择的目的”出发,实际上存在着三种方案,各方案又有优劣,从而产生了trade-off。本文比较了这三种方案,通过对数据交换时机的分析加强trade-off的意识。

定义

数据交换:在Exchanger的两方栅栏机制中,双方互相等待对方的数据。

如读线程在读取发生前持有“空缓存”,写线程在写入完成后持有“满缓冲”(“满”只表示写入完成),那么数据交换就是指将读线程的“空缓冲”与写线程的“满缓冲”交换。

方案比较

依据“时机选择的的目的”,存在三种方案:

方案1. 交换次数最少

交换次数最少的目的出发,交换行为应该发生在缓冲满和缓冲空时,这两种情况下都不得不发生交换,以满足最低的响应需求

缓冲满时(填充线程的缓冲),填充任务发现无法继续填充缓冲区,就发起交换,以减少数据(到空)继续填充;缓冲空时(清空线程的缓冲),清空任务发现无法继续清空,就发起交换,以增加数据(到满)继续清空。

也可以将实际的交换任务委派给专门的交换线程,填充任务和清空任务都向该线程申请执行交换。

方案2. 交换最及时(响应最及时)

响应最及时的目的出发,交换行为应该发生在缓冲刚增加数据和缓冲刚减少数据时,以满足“存在数据即交换”的最高的响应需求

这种方案相当于去掉了缓冲区。一方面,一旦缓存不空就立刻发生交换,交换后就没有了数据;另一方面,一旦缓存空就开始交换数据,交换后缓存就不空。看起来数据根本需要写入缓存就完成了交换。

也可以设置一个特别小的缓冲,比如1个字节。但交换区的缓冲减小,只会让交换双方各自维护的缓冲区加大。

方案3. 适度的交换频率和响应

很明显:交换次数最少的话,一些数据的处理过程就将延迟;响应最及时的话,交换频率太高,很浪费性能,甚至大型系统中耗电都会成为问题。

所以可采用折中的方案,达到适度的交换频率和响应交换行为发生在缓冲被填充到一定程度并保持一定时间 t 后,同时一旦缓冲满或缓冲空就立即发生交换

如果将时间 t 设置为 0,则退化为方案2;如果将时间 t 设置无穷大,则退化为方案1,从而既能兼容以上两种方案,又能根据实际响应需求静态配置,甚至根据实时的性能分析结果进行动态调整。

如果将Exchager比作“数据交换系统”,方案3即完成了对“数据交换系统”的trade-off,也就是基于成本(如耗电等)、收益(如延迟等)对系统设计作出的权衡、妥协。

总结

通过对三种Exchager数据交换时机的分析,加强了我们在系统设计中的trade-off意识。

《Java并发编程实战》中介绍了方案1和方案3。直接在书中看到方案1和方案3可能很难理解,但分析了上述trade-off过程后,就能轻松理解数据交换的时机了。

扫描微信关注我
微信公众号二维码
本文链接:从Exchager数据交换到基于trade-off的系统设计
作者:猴子007
出处:https://monkeysayhi.github.io
本文基于 知识共享署名-相同方式共享 4.0 国际许可协议发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名及链接。
我是猴子007,<br>一只非常特殊的动物,<br>可以从事程序的开发、维护,<br>经常因寻找香蕉或母猿而无心工作。