Как использовать ConcurrentLinkedQueue?

Как использовать ConcurrentLinkedQueue в Java?
Используя этот LinkedQueue, нужно ли беспокоиться о concurrency в очереди? Или мне просто нужно определить два метода (один для извлечения элементов из списка, а другой - для добавления элементов в список)?
Примечание: очевидно, эти два метода должны быть синхронизированы. Правильно?


EDIT: Я пытаюсь сделать следующее: у меня есть класс (на Java) с одним методом для извлечения элементов из очереди и другого класса одним методом для добавления элементов в очередь. Элементы, добавленные и извлеченные из списка, являются объектами моего собственного класса.

Еще один вопрос: мне нужно сделать это в методе remove:

while (queue.size() == 0){ 
  wait(); 
  queue.poll();
}

У меня есть только один потребитель и один производитель.

Ответ 1

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

Сначала создайте свою очередь:

Queue<YourObject> queue = new ConcurrentLinkedQueue<YourObject>();

Теперь, когда вы создаете свои объекты-производители/потребители, переходите в очередь, чтобы они могли куда-то помещать свои объекты (вместо этого вы могли бы использовать установщик для этого, но я предпочитаю делать такие вещи в конструкторе ):

YourProducer producer = new YourProducer(queue);

и

YourConsumer consumer = new YourConsumer(queue);

и добавьте материал в ваш продюсер:

queue.offer(myObject);

и напишите в своем потребителе (если очередь пуста, poll() вернет null, поэтому проверьте его):

YourObject myObject = queue.poll();

Подробнее см. Javadoc

EDIT:

Если вам нужно заблокировать ожидание очереди, чтобы она не была пустой, вы, вероятно, захотите использовать LinkedBlockingQueue и использовать(). Однако LinkedBlockingQueue имеет максимальную емкость (по умолчанию Integer.MAX_VALUE - более двух миллиардов) и, следовательно, может быть или не быть подходящим в зависимости от ваших обстоятельств.

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

Queue<YourObject> queue = Collections.synchronizedList(new LinkedList<YourObject>());

Кроме того, он блокирует экземпляр (очередь), поэтому вы можете синхронизировать свою очередь, чтобы обеспечить атомарность составных операций (как объяснил Джаред). Вы НЕ МОЖЕТЕ делать это с помощью ConcurrentLinkedQueue, поскольку все операции выполняются БЕЗ блокировки на экземпляре (с использованием переменных java.util.concurrent.atomic). Вам не нужно делать это, если вы хотите заблокировать, пока очередь пуста, потому что poll() просто возвращает значение null, пока очередь пуста, а poll() является атомарным. Проверьте, возвращает ли poll() значение null. Если да, подождите(), а затем повторите попытку. Не нужно блокировать.

В конце концов:

Честно говоря, я бы просто использовал LinkedBlockingQueue. Это все еще слишком много для вашего приложения, но вероятность того, что он будет работать нормально. Если он недостаточно эффективен (PROFILE!), Вы всегда можете попробовать что-то еще, и это означает, что вам не нужно иметь дело с ЛЮБОЙ синхронизированной информацией:

BlockingQueue<YourObject> queue = new LinkedBlockingQueue<YourObject>();

queue.put(myObject); // Blocks until queue isn't full.

YourObject myObject = queue.take(); // Blocks until queue isn't empty.

Все остальное - то же самое. Положите, вероятно, не будет блокировать, потому что вы вряд ли ставите два миллиарда объектов в очередь.

Ответ 2

Это в основном дубликат другого вопроса .

Здесь раздел ответа, относящийся к этому вопросу:

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

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

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

queue.add(obj);

или

queue.poll(obj);

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

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

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

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

Снова... атомные вызовы в очередь автоматически потокобезопасны. Неатомные вызовы не являются.

Ответ 3

Используйте poll, чтобы получить первый элемент, и add, чтобы добавить новый последний элемент. Что это, никакой синхронизации или чего-то еще.

Ответ 4

Вероятно, это то, что вы ищете с точки зрения безопасности потоков и "симпатии" при попытке уничтожить все в очереди:

for (YourObject obj = queue.poll(); obj != null; obj = queue.poll()) {
}

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

Ответ 5

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

Изменить: ConcurrentLinkedList на самом деле не просто оболочка, а скорее улучшенная параллельная реализация. В любом случае вам не нужно беспокоиться о синхронизации.

Ответ 6

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