2009-08-11 2 views
1

Я использую LinkedBlockingQueue для обработки объектов сообщений из других потоков. Например, у меня есть что-то вроде этого:Java: synchronized put() со списком объектов

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

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

При добавлении нового сообщения из другого потока, я называю message_queue.put (м). Нет проблем! Мой вопрос таков:

Как синхронизировать добавление набора сообщений одновременно? Скажем, я хочу сделать это:

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» в «синхронизированный (message_queue) {}» блок, но мне также нужно будет поместить тот же самый блок вокруг вызова .take()? И, очевидно, я не могу этого сделать, так как это мгновенно создаст тупиковую ситуацию, так как take() блокирует до тех пор, пока не будет добавлено новое сообщение(), чего не может произойти, если блокируется синхронизацией. Могу ли я пропустить синхронизированный блок при вызове take(), имея только синхронизированный блок в цикле put и получить желаемый эффект? Благодаря!

ответ

2

К сожалению, вы не можете получить доступ к отдельным замкам и замкам в пределах LinkedBlockingQueue, поскольку они являются частными.

Как вы упомянули, вы могли бы просто обернуть операцию массового ввода в блок synchronized, который сделал бы это атомарным. Если вы это сделаете, я не понимаю, почему вы заявляете, что вам также необходимо добавить блок вокруг операции take(). Я не верю, что этот второй синхронизированный блок понадобится (поскольку LinkedBlockingQueue в любом случае является потокобезопасным).

+0

согласился: единственная проблема с заказом: 2 операции массового ввода сталкиваются друг с другом или с одной транзакцией. –

2

Возможно, объект, который вы хотите положить в очередь (и взлет), будет группой сообщений?

Возможно, у вас есть объект, представляющий упорядоченный набор сообщений. Обычно он содержит только одно сообщение, но может (в этом случае) содержать много. Это будет поддерживать атомарность и порядок.

+0

+1 bah ... Я все еще печатал свой ответ :(избил меня до него – basszero

+0

хорошая идея, но это усложняет ситуацию, если вы хотите снять 1 сообщение за раз. –

Смежные вопросы