异步通讯的API
,它为标准消息协议和消息服务提供了一组通用接口,包括创建、发送、读取消息等,用于支持JAVA应用程序开发。接收者不需要在线
。服务器发送了消息,然后就不管了,等到客户端上线的时候,能保证接收到服务器发送的消息。这是一个很强大的解决方案,能处理当今世界很多普遍问题。避免重复投递,无需考虑幂等操作
)轮胎:RingBuffer:环形缓冲区
1. 数组,取余覆盖的环形存储方式,不需要花费大量的时间用于内存清理/垃圾回收(避免频繁的GC)。由于涉及到取模操作,为了CPU进行位运算更加高效,RingBuffer的大小应该是2的N次方。
2. 生产者/消费者模式下disruptor号称“无锁并行框架”(BlockingQueue是利用了Lock锁机制来实现),生产者维护一个生产指针P,消费者维护一个消费者指针C,当然P和C本质上就是序号。两者各操作各的,不需要锁,需要注意的是生产者和消费者的速度问题,在disruptor内部已经为我们做了处理,就是判断一下P和C之间不能超过一圈的大小。(保持适当距离,不要越界距离超过一圈)
2.1 一个生产者 + 一个消费者:保证 生产者 与 消费者 不超过一圈的距离。
2.2 一个生产者 + 多个消费者:多个消费者当然持有多个消费指针C1,C2,...,保证生产者的速度“协调”最慢的消费者的速度,也是不能超出一圈的概念。
2.3 多个生产者 + N个消费者:无论生产者有几个,生产者指针P只能存在一个,否则数据就乱套了。多个生产者之间共享一个P指针,在disruptor中实际上是利用了CAS机制来保证多线程的数据安全,也没有使用到锁。
备注:RingBuffer的指针cursor就是一个volatile变量。Ringbuffer是一个环状数组,数组中每一位是一个Entry,每个Entry有它的sequence,当生产者对ringbuffer调用commit,会将cursor更新为该sequence,由于内存屏障的存在,其他所有线程CPU缓存的cursor都会更新为最新的数据(或者缓存失效),这样一来,消费者们就会获得最新的cursor。
3. 通过sequence访问数组,比链表更快。因为在内存上也是连续存储的,对CPU的缓存也更加友好,在硬件级别上,数组可以被预加载,CPU不用每次去主存储器加载数组中下一个元素。
需要I/O时采用nio异步调用,不阻塞disruptor消费者线程
,等到I/O异步调用回来后在回调方法中将后续处理重新塞到disruptor队列中,可以看出来,这是典型的事件处理架构,确实能在时间上占据优势,加上ringBuffer固有的几项性能优化,能让disruptor发挥最大功效。