Java:将put()与对象列表同步

时间:2009-08-11 16:19:06

标签: java multithreading

我正在使用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(),这在同步锁定时不会发生。我可以在take()调用上跳过synchronized块,在put循环中只有一个synchronized块,并获得所需的效果吗?谢谢!

2 个答案:

答案 0 :(得分:2)

您想要放入队列(并取消)的对象可能是消息的吗?

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

答案 1 :(得分:2)

很遗憾,您无法访问LinkedBlockingQueue内的个人投放和锁定,因为它们是私有的。

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