Многопоточный наблюдатель в Java - сохранить правильный порядок

Я реализую то, что я бы назвал «Наблюдаемый набор». Это просто обычный набор, но у него могут быть некоторые наблюдатели, которые уведомляются о добавлении новых элементов.

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

Каков наилучший подход?

Самый наивный - поместить добавление и информирование в "синхронизированный" блок. Но я считаю, что это может быть медленным и т. д.

Во-вторых, я пытался просто добавить элемент в набор и добавить его в «очередь информирования». При каждом добавлении элемента проверялось, включено ли информирование. Если нет, то он запускался до тех пор, пока очередь не опустеет. Это работало вполне нормально, но я боялся, что это нехороший подход.

Последнее, что я реализовал, я бы назвал «информирующими потоками». При добавлении наблюдателей у каждого наблюдателя создается собственный «поток информирования». Этот поток работает в фоновом режиме и проверяет, находится ли он в конце глобальной «очереди информирования». Если это не так, он информирует конкретный поток о новых элементах. Однако у меня проблемы с синхронизацией и циклом while(true). Я не знаю, как установить условие для завершения потока. Следующая проблема, которую я заметил при написании, заключается в том, что каждый новый поток будет проинформирован с самого начала... Это нехорошо.

Надеюсь, я достаточно хорошо все описал. Если нет, дайте мне знать, я постараюсь исправить. Как лучше всего выполнить эту задачу? Спасибо!


person Bóg Programowania    schedule 27.02.2015    source источник
comment
Самый наивный - поместить добавление и информирование в синхронизированный блок. Но я считаю, что это может быть медленным и т. Д. Вы действительно пробовали, чтобы увидеть, медленно ли это?   -  person Sizik    schedule 27.02.2015
comment
@ Сизик прав. всегда идите с простотой, пока не узнаете, что требуется оптимизация.   -  person Martin Serrano    schedule 27.02.2015
comment
Что ж, я пробовал :) Но это не разрешено тем, для кого я это делаю. Это будет медленно, потому что при добавлении вам придется ждать, пока все наблюдатели будут проинформированы, чтобы добавить следующий элемент, в то время как это может быть сделано другим потоком, например, в то же время.   -  person Bóg Programowania    schedule 27.02.2015


Ответы (1)


Ваше второе решение можно улучшить, используя BlockingQueue: с ним не нужно проверять "включено ли информирование", вы просто вызываете take(), и он будет ждать появления чего-то в очереди.

Вы также можете изучить проект RxJava. Это несколько сложно, но в нем есть много функций, которые могут вам понадобиться.

Он расширяет шаблон наблюдателя для поддержки последовательностей данных/событий и добавляет операторы, которые позволяют вам декларативно составлять последовательности вместе, абстрагируясь от проблем, связанных с такими вещами, как низкоуровневая многопоточность, синхронизация, безопасность потоков и параллельные структуры данных.

person lbalazscs    schedule 27.02.2015
comment
Спасибо за идею. Это также может улучшить 3-е решение. - person Bóg Programowania; 27.02.2015