4.0 中新的 ChangeBus早在去年秋天,我们知道老的 ChangeBus 能够被改进并讨论了一些可能的方法。讨论的这些想法中有一个具备很大潜力:使用一个环形缓冲区。 环形缓冲区其实很简单。概念上,它可以被认为是一个单一的循环缓冲区,在一个单一的游标下,一或多个生产者可以添加条目(以线程安全的方式)到缓冲区中,消费者尾随游标和过程(每个在它们自己的线程内)访问已经保存在缓存中的每个条目。 ChangeSets 被添加在游标处,消费者线程跟在后面阅读它们。 在上图中,数字代表的是缓冲中各项的位置,从1开始,逐次增加。光标的位置是7,读取ChangeSet的每个消费者线程处在各自不同的位置:6、4、3和2 。注意:紧跟在所有消费者线程后面的是垃圾回收线程,它只是对所有消费者线程都读取了的ChangSet引用清空。(我们需要这样的线程,因为环形缓冲通常只有1024或者2048个存储项,而且假设每个环形缓冲区都有具有许多更新的ChangSet的话,就会占用大量内存。环形缓冲的垃圾回收器可以通过JVM对已经处理完成的ChangeSet对象进行回收。) 下图是另一个环形缓冲图,这张图表示的是在另外添加了7个ChangeSet对象,并且{敏感词}的消费者线程前移后的状态。
其中光标和所有的消费者线程以及垃圾回收器都已经前移。
每个消费者位置与其余消费者的位置是毫不相关的,然而,它们的位置很明显与可添加新变更项的光标位置相关。通常,{敏感词}运行的非常快,以致于消费者都紧随在光标之后。当然,也存在其他情况,比如每个ChangeSet中包含的变更数量起伏很大的时候(通常都是这样的)。
添加的ChangeSet对象越多,光标前移的就会越快,这样就有可能抵达“环形缓冲开始“的地方,此时就会开始重用缓冲区中以前已经使用的缓冲项了。(实际上,缓冲区是一个简单的预先分配了固定大小的Object[],缓冲区的位置可以很容易地被认为是数组的索引。我们只是把它想象为一个环形缓冲区。)
光标最终将会重用不再需要的缓冲区中的各项。 |