如何使用disruptor模式实现解复用器?

时间:2014-05-23 12:36:02

标签: java queue real-time message-queue disruptor-pattern

我希望有一个环形缓冲区队列,它将接收对象并将它们分布在线程池中的多个线程中,在单个生产者中分配给多个消费者方式。如何使用disruptor模式实现这一目标?任何HelloDemux代码示例?感谢!!!

1 个答案:

答案 0 :(得分:6)

这个article详细介绍了实现disruptor模式的解复用器的所有内容,但我认为线程池意味着你需要一个与disruptor模式相反的调度程序。要实现demux,您需要设置固定数量的使用者线程,而不是池,并让它们从队列尾部获取消息。 现在,您可能会问,如果没有调度员,他们怎么能这样做呢?他们只是忙着旋转(或使用其他一种等待策略,即旋转,屈服,停车,睡眠等组合。 )在队列尾巴周围。 现在,您可能会问,他们怎么能在不相互衔接的情况下做到这一点?那么您有两个选择:您可以使用MODULUS(无锁)或CAS(轻锁)。每个人都有自己的优点和缺点。 MODULUS很快,但如果一个消费者落后,可能会引起车道争用。 CAS不是那么快,但不会引起车道争用。

package com.coralblocks.coralqueue.sample.demux;

import com.coralblocks.coralqueue.demux.CASAtomicDemux;
import com.coralblocks.coralqueue.demux.Demux;

public class Sample {

    private static final int NUMBER_OF_CONSUMERS = 4;

    public static void main(String[] args) throws InterruptedException {

        final Demux<StringBuilder> queue = new CASAtomicDemux<StringBuilder>(1024, StringBuilder.class, NUMBER_OF_CONSUMERS);

        Thread[] consumers = new Thread[NUMBER_OF_CONSUMERS];

        for(int i = 0; i < consumers.length; i++) {

            final int index = i;

            consumers[i] = new Thread() {

                @Override
                public void run() {

                    boolean running = true;

                    while(running) {
                        long avail;
                        while((avail = queue.availableToPoll(index)) == 0); // busy spin
                        for(int i = 0; i < avail; i++) {
                            StringBuilder sb = queue.poll(index);

                            if (sb == null) break; // mandatory for demuxes!

                            if (sb.length() == 0) {
                                running = false;
                                break; // exit immediately...
                            } else {
                                System.out.println(sb.toString());
                            }
                        }
                        queue.donePolling(index);
                    }
                }
            };

            consumers[i].start();
        }

        StringBuilder sb;

        for(int i = 0; i < 10; i++) {
            while((sb = queue.nextToDispatch()) == null); // busy spin
            sb.setLength(0);
            sb.append("message ").append(i);
            queue.flush();
        }

        // send a message to stop consumers...
        for(int i = 0; i < NUMBER_OF_CONSUMERS; i++) {
            // because the consumer exit immediately on this message, each
            // consumer will get one of these messages and exit...
            while((sb = queue.nextToDispatch()) == null); // busy spin
            sb.setLength(0);
        }
        queue.flush(); // sent batch

        for(int i = 0; i < consumers.length; i++) consumers[i].join();
    }
}