【问题标题】:Java: synchronized put() with a list of objectsJava:将 put() 与对象列表同步
【发布时间】:2010-11-18 16:30:08
【问题描述】:

我正在使用 LinkedBlockingQueue 来处理来自其他线程的消息对象。例如,我有这样的事情:

LinkedBlockingQueue<Message> message_queue = new LinkedBlockingQueue<Message>();

public void run(){
    while(true){
        Message m = message_queue.take();
        handle_message(m);
    }
}

当我从另一个线程添加新消息时,我调用 message_queue.put(m)。没问题!我的问题是这样的:

如何一次同步添加一组消息?假设我想这样做:

Message[] messages = {/* some list of message objects */};
for (Message m : messages){
    message_queue.put(m);
}

问题是另一个线程可能正在做同样的事情,并且不能保证来自一个线程的消息完全按照我的意图排队。来自竞争线程的消息可以在两者之间“交错”(即实际序列可能最终是 A、A、B、B、A、B 而不是预期的 A、A、A、B、B、B)我知道我可以将“put”示例中的循环放入“synchronized(message_queue){}”块中,但我是否还需要将相同的块放在对 .take() 的调用周围?很明显,我不能这样做,因为它会立即造成死锁情况,因为 take() 会阻塞,直到有新的 Message 被 put() ,这在被同步锁定时不会发生。我可以跳过 take() 调用上的同步块,在 put 循环上只有一个同步块,并获得所需的效果吗?谢谢!

【问题讨论】:

    标签: java multithreading


    【解决方案1】:

    也许您想要放入队列(并起飞)的对象将是一个消息?

    即也许您有一个表示有序消息集合的对象。通常它只包含一条消息,但可以(在这种情况下)包含许多消息。这将保持原子性和有序性。

    【讨论】:

    • 好主意,但如果您想一次发送 1 条消息,它确实会使事情复杂化。
    【解决方案2】:

    很遗憾,您无法访问 LinkedBlockingQueue 中的个人 put 和 take 锁,因为它们是私有的。

    正如您所提到的,您可以简单地将批量放置操作包装在 synchronized 块中,这将使该操作成为原子操作。如果你这样做,我不明白你为什么说你还需要在take() 操作周围添加一个synchronized 块。我认为不需要第二个同步块(因为 LinkedBlockingQueue 无论如何都是线程安全的)。

    【讨论】:

    • 同意:唯一的排序问题是 2 个批量 put 操作是相互冲突还是与单个 put 操作发生冲突。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-09-05
    • 2011-07-19
    • 2014-03-11
    • 1970-01-01
    • 2011-12-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多