LinkedBlockingQueue 的 Java 性能问题

2022-09-03 05:19:11

这是我关于堆栈溢出的第一篇文章...我希望有人能帮助我

我对Java 6有很大的性能回归。在第一个线程中,我生成一些对象,并将其推入队列在第二个线程中,我将这些对象拉出。当频繁调用 的方法时,会发生性能回归。我监视了整个程序,该方法总体上占用了最多的时间。吞吐量从 ~58Mb/s 到 0.9Mb/s...LinkedBlockingQueuetake()LinkedBlockingQueuetake()

队列弹出并采用使用此类中的静态方法调用的方法 ar

public class C_myMessageQueue {

    private static final LinkedBlockingQueue<C_myMessageObject> x_queue = new LinkedBlockingQueue<C_myMessageObject>( 50000 );

    /**
     * @param message
     * @throws InterruptedException
     * @throws NullPointerException
     */
    public static void addMyMessage( C_myMessageObject message )
            throws InterruptedException, NullPointerException {
        x_queue.put( message );
    }

    /**
     * @return Die erste message der MesseageQueue
     * @throws InterruptedException
     */
    public static C_myMessageObject getMyMessage() throws InterruptedException {
        return x_queue.take();
    }
}

我如何调整方法以完成至少25Mb / s,或者是否有其他类可以使用,当“队列”已满或为空时,它将阻塞。take()

亲切问候

巴特

P.S.:抱歉我的英语不好,我来自德国;)


答案 1

您的生产者线程只是放置的元素多于使用者消耗的元素,因此队列最终会达到其容量限制,因此生产者会等待。

从现在开始,巩固我原来的答案,我们基本上有了全貌:

  • 通过执行极快的 s,您达到了 (每个队列都有一个)的固有吞吐量限制,即使连续 (零进一步处理) 也无法跟上。(顺便说一句,这表明在这种结构中,无论如何,在您的JVM和机器上,put()s至少比读取稍微昂贵一些)。LinkedBlockingQueueput()take()s
  • 由于有一个特定的锁是使用者锁定的,因此放置更多的使用者线程可能无济于事(如果您的使用者实际上正在执行某些处理并且限制了吞吐量,那么添加更多使用者会有所帮助。对于具有多个使用者(或生产者)的场景,有更好的队列实现,您可以尝试 , 和即将推出的 jsr166y)。SynchronousQueueConcurrentLinkedQueueTransferQueue

一些建议:

  • 尝试制作更粗粒度的对象,以便将每个对象排队的开销与从生产线程中卸载的实际工作平衡(在您的情况下,您似乎为表示工作量微不足道的对象创建了大量的通信开销)
  • 你也可以让生产者通过卸载一些消耗性的工作来帮助消费者(当有工作要做时,无所事事地等待没有多大意义)。

/更新后约翰W.正确地指出我原来的答案是误导性的


答案 2

我通常建议不要在对性能敏感的代码区域中使用LinkedBlockingQueue,而是使用ArrayBlockingQueue。它将提供更好的垃圾回收配置文件,并且比LinkedBlockingQueue更有利于缓存。

尝试数组阻止队列并测量性能。

LinkedBlockingQueue的唯一优点是它可以是无限的,但是这很少是你真正想要的。如果存在使用者失败且队列开始备份的情况,则具有有界队列允许系统正常降级,而不是冒着队列未限时可能发生的 OutOfMemoryErrors 的风险。


推荐