多消费者无锁队列的实现

时间:2019-04-30 21:04:52

标签: java multithreading queue lock-free

最近,我遇到了一个问题:假设有3个使用者线程,并且需要实现无锁队列(不能使用同步),以便不消耗线程被阻止。假设该队列已包含数据。

我考虑了一会儿,遇到了 Atomic 操作,如果使用得当,会有所帮助。我的实现如下所示。由于队列中已经有数据,因此我尚未实现enqueue方法并没有在构造函数中填充数组。

public class SPMCQueue {

    private AtomicInteger index = new AtomicInteger(0);

    public int[] arr;

    public SPMCQueue(int size) {
        arr = IntStream.range(0, size).toArray();
    }

    public Integer dequeue() {
        Integer ret = null;
        int x = index.getAndIncrement();
        if (x < arr.length) {
            ret = arr[x];
            System.out.println(arr[x] + " by " + Thread.currentThread().getName());
        }
        else {
            throw new RuntimeException("Queue is empty");
        }
        return ret;
    }
}

class QueueTest {
    public static void main(String[] args) {

        SPMCQueueq = new SPMCQueue(40);

        Runnable t1 = () -> {
            try {
            while (true) {
                q.dequeue();
            }
            }catch(Exception e) {

            }
        };

        Runnable t2 = () -> { 
            try {
            while(true) { q.dequeue(); }
            }catch(Exception e) {

            }
        };

        Runnable r3 = () -> { 

            try {
                while(true) { q.dequeue(); }
            } catch (Exception e) {
                // TODO Auto-generated catch block
                //e.printStackTrace();
            }

        };

        Thread thread1 = new Thread(t1);
        Thread thread2 = new Thread(t2);
        Thread thread3 = new Thread(r3);

        thread1.start();
        thread2.start();
        thread3.start();

    }
}

我已经执行了上面的程序,结果显示所有3个使用者都按顺序使用了数据,并且某些线程比其他线程消耗的数据更多,但是我看不到任何数据多次出现在o / p中。

我有以下问题:

  1. 上述实现中是否存在任何问题?

  2. 实现无锁消费者队列的其他方法有哪些?

1 个答案:

答案 0 :(得分:0)

我想与答案https://stackoverflow.com/a/21101904/7340499一并给出答案,因为这与您的问题类似。

所以,你的问题:

  

但是我看不到o / p中多次出现任何数据。

这是预期的。因为getAndIncrement()是原子的,所以每次访问该函数时,您将获得不同的x值,因此得到不同的输出。 但是,由于在单个非原子出队操作中结合了“ getAndIncrement()”和“ System.out.print()”功能,因此有时您的输出可能会出现故障,例如您在一个线程上得到x = 1,而另一个线程中断,得到x = 2并打印出来,然后您的初始线程完成打印。我相信,这也指出了实现的问题,如(1)所述。您的应用程序可以正常处理队列吗?

  

实现无锁消费者队列的其他方法有哪些?

您已经注意到,原子操作是一种方法。但从本质上讲,无论如何它们都非常像锁。它们只是在较小的规模上运行(尽管存在一些实现差异)。因此,很难将它们概念化为不同的方法,至少对于我自己而言。除此之外,我相信这里还有一些不错的资源:Lock Free Queue -- Single Producer, Multiple Consumers