LinkedBlockingQueue的Java性能问题

lof*_*ses 15 java queue performance multithreading

这是我在stackoverflow上的第一篇文章...我希望有人可以帮助我

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

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

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

如何调整take()方法以达到至少25Mb/s,或者是否有一个我可以使用的类,它将在"队列"满或空时阻塞.

亲切的问候

巴特

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

Dim*_*eou 16

您的生产者线程只是放置了比消费者消耗的元素更多的元素,因此队列最终达到其容量限制,因此生产者等待.

从现在起巩固我原来的答案我们基本上已经全面了解:

  • LinkedBlockingQueue通过执行极快的put()s 来达到(每个队列都有一个)的固有吞吐量限制,即使是连续的take()s,没有进一步处理,也无法跟上.(顺便说一下,这表明在这个结构中,无论如何,在你的JVM和机器上,put()s至少比读取的成本稍高一些).
  • 由于存在消费者锁定的特定锁定,因此放置更多的消费者线程可能无法提供帮助(如果您的消费者实际上正在进行某些处理并且限制了吞吐量,那么添加更多消费者将有所帮助.对于具有更好的队列实现不止一个消费者(或生产者),你可以尝试SynchronousQueue,ConcurrentLinkedQueue以及即将TransferQueuejsr166y的).

一些建议:

  • 尝试制作更粗粒度的对象,以便排队每个对象的开销与从生成线程卸载的实际工作相平衡(在您的情况下,似乎您为代表可忽略不计的工作量的对象创建了很多通信开销)
  • 你也可以让生产者通过卸载一些消费工作来帮助消费者(当有工作要做时,没有多少时间等待.)

/在John W.正确地指出我的原始答案是误导之后更新


Mic*_*ker 5

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

尝试使用 ArrayBlockingQueue 并测量性能。

LinkedBlockingQueue 的唯一优点是它可以是无界的,但这很少是您真正想要的。如果您遇到消费者失败并且队列开始备份的情况,则有界队列允许系统优雅地降级,而不是冒可能在队列无界时发生 OutOfMemoryErrors 的风险。


Dev*_*ler 5

这里有几件事可以尝试:

更换LinkedBlockingQueue用的ArrayBlockingQueue。它没有悬空引用,因此在队列填满时表现更好。具体来说,考虑到 LinkedBlockingQueue 的 1.6 实现,在队列实际变空之前不会发生元素的完全 GC。

如果生产者端始终优于消费者端,请考虑使用draindrainTo执行“批量”获取操作。

或者,让队列采用消息对象的数组或列表。生产者用消息对象填充列表或数组,每个放置或获取以相同的锁定开销移动多个消息。把它想象成一个秘书递给你一堆“当你外出时”的信息,而不是一次递给你一个。