在尾部和头部使用一个锁实现ArrayBlockingQueue的原因是什么?

时间:2018-06-07 11:22:17

标签: java concurrency java.util.concurrent blockingqueue

我在实践中阅读Java Concurrency,现在我在页面上关于LinkedBlockingQueue与ArrayBlockingQueue的对比,我发现了这个文本

  

此测试表明LinkedBlockingQueue比ArrayBlockingQueue更好地扩展。这可能看起来很奇怪:链接队列必须为每个插入分配一个链接节点对象,因此似乎比基于数组的队列做更多的工作。但是,即使它有更多的分配和GC开销,链接队列允许通过put和take比基于阵列的队列更多的并发访问,因为   最佳链接队列算法允许头部和尾部独立更新。因为通常是分配   threadlocal,通过进行更多分配可以减少争用的算法通常可以更好地扩展。(这是另一个   基于传统性能调优的直觉与可伸缩性所需的直觉相反的实例。)

带有这样的图像

enter image description here

我已经深入研究了ArrayBlockingQueue的源代码,并且确实发现了put()take()操作的单锁(事实上,通过语义,我只发现了用于访问计数字段的同步,哪里有关于当前内容的队列大小的信息)。

put方法的代码

public void put(E e) throws InterruptedException {
        checkNotNull(e);
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            while (count == items.length)
                notFull.await();
            enqueue(e);
        } finally {
            lock.unlock();
        }
    }

我的问题是:使用两个锁而不是一个用于尾部和头部的锁来实现ArrayBlockingQueue的障碍是什么。我可以想象一些算法,它可以检查前面是否有一些地方可以移动下一个地方,然后放置下一个地方;

put()检查与take()所在位置是否相等以及是否等于put()正在等待take()完成同等操作。它似乎将起作用,因为put()take()在某种意义上具有沿阵列移动的恒定方向。当然,我们应该通过一些布尔标志来考虑初始状态。

当然,显然目前ArrayBlockingQueue的吞吐量比LinkedBlockingQueue更差,因为争用更多,因此代码更加加密(Amdal定律)。但是用两个锁编写它并且使用它也有一个较小的分配时间可能会有什么问题!

抱歉我的英语不好,提前!

0 个答案:

没有答案