jdk1.8观察者、被观察者,其设计在个人理解更适合批处理
继去年写得jdk1.8观察者、被观察者文章(https://www.cnblogs.com/SaltFishYe/p/11619402.html)之后,有了点新想法。
背景
使用源码的观察者和被观察者呢是之前和同时开发一个类似数据处理的中间件的玩意,从最初的架构设计的讨论到从0开发,其中有过2个废气架构版本和现在的终版1.0。
简单描述一下做得这个玩意就是相当于一个流、批统一计算中间件,做了一个可以动态手动配置的链式处理架构,其中这个链就是基于观察者和被观察者。链内的每个节点都既是观察者也是被观察者。从源头数据通知观察者,观察者接收到数据处理,于此同时此观察者也是被观察者,又可以通知后续观察者。
刚刚描述的批和流在本人应用中详细解释如下:
批:执行一条sql(ignite),然后把所有查出来的数据对象做成一个row(自定的数据处理对象)对象,然后发给后续节点
流:kafka发来的数据即是发送给后续节点
想法
从背景上就可以看出,无论是“批”还是“流”,但是把单条数据发给后续节点处理,所以从更细粒的程度来说,其实是“批”和“流”都是“流”,只不过来源不同,在多线程状态下就发现了去年文章所写的线程不安全现象。
之后就本人团队简单的开发了一个观察者和被观察者的接口和抽象类,jdk源码提供的就启用掉。
后续的开发和一些其他功能的开发给本人带来了一些灵感,jdk源码的观察者和被观察者不适合“流”处理,那么在“批”处理中呢,经过简单的思考,发觉很适用“批”处理。
灵感
在之后的设计开发中,本人亲自设计和开发了一个动态线程处理模型,给出一个固定线程池,一个轮询线程定时轮询,监控单个线程处理的数据量,处理数据使用的时间,提供出监控日志,并动态关闭线程或者加入更多线程,设计重点在于:参与计算逻辑的线程,为了效率原因,不去竞争任何多线程共享的资源,记录的数据都是“只写”操作,不去在乎轮询线程用这些数据干啥,而轮询线程,对于各个线程的数据也基本是“只读”操作,不去在乎计算逻辑的线程怎么写入数据,这样在保证无锁的情况下多线程数据能一起参与计算,这个设计很适合用在Jdk源码的观察者和被观察者中。
设计
当时发现jdk源码的观察者和被观察者changed用来标记是否产生“动作”来判断是否通知观察者时就很奇怪,这个设计用来干啥的,当然现在也不知道,但是从上述描述中可知,被观察者想要通知观察者,实际做了两步动作,一个是修改changed=true,一个是通知被观察者,那么这两个动作完全可以通过两个线程处理。
与灵感以相同,观察者负责标记自身的变化和记录变化的数据row,但是再“批”设计中,可以容纳多次变化数据,做成一个List<Row>,那么被观察者只负责追加“动作”记录和标记变化changed=true,再有轮询线程负责通知观察者。
后话
这里只写了一个利用轮询线程做“批”处理的思路,实际上设计很多,完全可以放弃轮询线程,多个线程做轮询或者空闲时直接通知观察者,但是这样做的话,可能就要考虑更多线程安全性的问题,基本上还是要加锁处理,这样的话,就是在jdk源码的观察者和被观察者外加了更多设计来使得源码满足设计模型,与其这样完全可以重新写一套自己的观察者和被观察者,而不是在不牢固源码的上加太多东西使其牢固,所以复杂的设计这里不再过多描述,更多的设计欢迎讨论。
posted on 2020-06-21 14:22 SaltFishYe 阅读(151) 评论(0) 编辑 收藏 举报