java.util.ConcurrentLinkedQueue - PullRequest
       20

java.util.ConcurrentLinkedQueue

16 голосов
/ 12 января 2009

Я хочу использовать java.util.ConcurrentLinkedQueue в качестве недолговечной очереди для сервлета. Вот реклама из Javadoc для класса.

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

Теперь представьте, что у меня есть 1000 одновременных запросов к сервлету, и каждому потоку нужно будет вставить объект в ConcurrentLinkedQueue. Из описания я должен сделать вывод, что у него не будет проблем с обработкой нагрузки? Мне понадобится гарантия:

  1. Я автоматически получаю поточно-гарантированную гарантию без необходимости выполнять собственную синхронизацию.
  2. Я не потеряю ни одного запроса, если нагрузка трафика превысит 1000 одновременных запросов.

Спасибо

Ответы [ 4 ]

56 голосов
/ 12 января 2009

По сути, вы задаете три разных вопроса (два из них явно и один неявно.) Вот они с моими ответами:

1. Нужно ли выполнять собственную синхронизацию, если я использую java.util.ConcurrentLinkedQueue?

Атомарные операции над параллельными коллекциями синхронизируются для вас. Другими словами, каждый отдельный вызов в очереди гарантированно поддерживает поток без каких-либо действий с вашей стороны. То, что не гарантировано поточно-безопасным, это любые неатомарные операции, которые вы выполняете над коллекцией.

Например, это потокобезопасно без каких-либо действий с вашей стороны:

queue.add(obj);

или

queue.poll(obj);

Тем не менее, неатомарные вызовы в очередь не являются автоматически поточно-ориентированными. Например, следующие операции не автоматически поточно-ориентированы:

if(!queue.isEmpty()) {
   queue.poll(obj);
}

Этот последний не является потокобезопасным, поскольку вполне возможно, что между временем вызова isEmpty и вызовом опроса времени другие потоки будут добавлять или удалять элементы из очереди. Потоковый способ сделать это выглядит так:

synchronized(queue) {
    if(!queue.isEmpty()) {
       queue.poll(obj);
    }
}

Опять же ... атомарные вызовы в очередь автоматически поточно-ориентированы. Неатомарные звонки - нет.

2. Я гарантированно не потеряю звонки на java.util.ConcurrentLinkedQueue, если есть 1000 одновременных запросов?

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

3. Будет ли java.util.ConcurrentLinkedQueue работать достаточно хорошо?

Обычно мы говорим о «правильности», когда говорим о параллелизме. Я имею в виду, что классы Concurrent гарантируют, что они поточнобезопасны (или устойчивы к тупику, голоданию и т. Д.). Когда мы говорим об этом, мы не даем никаких гарантий в отношении производительности (как быстро вызывается коллекция являются) - мы только гарантируем, что они «правильные».

Тем не менее, ConcurrentLinkedQueue - это реализация без ожидания, так что это, вероятно, настолько эффективно, насколько это возможно. Единственный способ гарантировать производительность загрузки вашего сервлета (включая использование параллельных классов) - это проверить его под нагрузкой.

3 голосов
/ 12 января 2009

Помните, что очередь безопасна только для потоков для звонков одному участнику. Не пишите такой код и ожидайте, что он будет работать:

if (queue.Count!=0)
    queue.Dequeue().DoSomething();

В промежутке между этими двумя операциями другой поток мог удалить из очереди последний элемент. Я не знаком с коллекциями Java, но думаю, что Dequeue в таком случае вернет null, что даст вам исключение.

1 голос
/ 12 января 2009
  1. Поскольку очередь является поточно-ориентированной, вам не нужно выполнять какие-либо синхронизации для обеспечения ее безопасности. Однако вы должны убедиться, что все потоки имеют равный доступ к очереди, чтобы избежать голодания, ожидания занятости и т. Д. *

  2. Поскольку очередь не ограничена, размер очереди ограничен только объемом доступной памяти.

0 голосов
/ 12 января 2009

Да, на ваши два вопроса.

Параллельная очередь является поточно-безопасной (и эффективна из-за алгоритма без блоков, используемого ниже). Потокобезопасный подразумевает , что число одновременных обращений не должно иметь значение (я еще не слышал о состоянии гонки, которое гарантированно не происходить ниже xyz одновременного доступа).

Кроме этого, оптимальная производительность в многопоточных приложениях более сложна, чем эта. Но использование реальной параллельной коллекции не так уж плохо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...