Как использовать ConcurrentLinkedQueue?
как я могу использовать ConcurrentLinkedQueue в Java?
Используя это LinkedQueue, мне нужно беспокоиться о параллелизме в очереди? Или мне просто нужно определить два метода (один для повторного извлечения элементов из списка, а другой для добавления элементов в список)?
Примечание: очевидно, что эти два метода должны быть синхронизированы. Верно?
EDIT: что я пытаюсь сделать, это: у меня есть класс (в Java) с одним методом для извлечения элементов из очереди и другой класс с помощью одного метода для добавления элементов в очередь. Элементы добавляются и извлекаются из списка являются объектами моего собственного класса.
еще один вопрос: мне нужно сделать это в метод remove:
while (queue.size() == 0){
wait();
queue.poll();
}
у меня только один потребитель и один производитель.
6 ответов:
нет, методы не нужно синхронизировать, и вам не нужно определять какие-либо методы; они уже находятся в 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, и использовать метод take (). Однако LinkedBlockingQueue имеет максимальную емкость (по умолчанию Integer.MAX_VALUE, который составляет более двух миллиардов) и, следовательно, может быть или не быть подходящим в зависимости от ваших обстоятельств.
если у вас есть только один поток, помещающий вещи в очередь, а другой поток, вынимающий вещи из очереди, ConcurrentLinkedQueue, вероятно, является излишним. Это больше для того, когда вы можете иметь сотни или даже тысячи потоков одновременно обращаются к очереди. Ваши потребности, вероятно, будут удовлетворены с помощью:
Queue<YourObject> queue = Collections.synchronizedList(new LinkedList<YourObject>());плюс этого заключается в том, что он блокирует экземпляр (очередь), поэтому вы можете синхронизировать очередь, чтобы обеспечить атомарность составных операций (как объяснил Джаред). Вы не можете сделать это с ConcurrentLinkedQueue, так как все операции выполняются без блокировки экземпляра (с помощью java.утиль.параллельный.атомарная переменная.) Вам не нужно будет этого делать, если вы хотите блокировать пока очередь не станет пустой, потому что опрос() будет просто возвращать значение null, в то время как очередь пуста, и poll() является атомарным. Проверьте, возвращает ли функция poll () значение null. Если это так, Подождите (), а затем повторите попытку. Нет необходимости запирать.
и наконец:
честно говоря, я бы просто использовать LinkedBlockingQueue. Это все-таки перебор для вашего приложения, но скорее всего он будет работать нормально. Если он недостаточно эффективен (профиль!), вы всегда можете попробовать что-то еще, и это означает, что вам не придется иметь дело с Любые синхронизированные вещи:
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.все остальное то же самое. Поставить наверное не будет блокировать, потому что вы вряд ли поставите два миллиарда объектов в очередь.
это в значительной степени дубликат другой вопрос.
вот раздел этого ответа, который имеет отношение к этому вопросу:
мне нужно сделать свою собственную синхронизацию, если я использую java.утиль.Двухсторонней?
атомарные операции над параллельными коллекциями синхронизируются для вас. Другими словами, каждый отдельный вызов очереди гарантирован потокобезопасным без каких-либо действий с вашей стороны. Что не гарантированная потокобезопасность-это любые операции, выполняемые над коллекцией, которые не являются атомарными.
например, это threadsafe без каких-либо действий с вашей стороны:
queue.add(obj);или
queue.poll(obj);однако; неатомные вызовы очереди не являются автоматически потокобезопасными. Например, следующие операции не автоматически threadsafe:
if(!queue.isEmpty()) { queue.poll(obj); }этот последний не является потокобезопасным, так как он очень возможно, что между вызовом времени isEmpty и вызовом опроса времени другие потоки добавят или удалят элементы из очереди. Потокобезопасный способ выполнить это выглядит следующим образом:
synchronized(queue) { if(!queue.isEmpty()) { queue.poll(obj); } }снова...атомарные вызовы очереди автоматически потокобезопасны. Неатомные вызовы-нет.
Это, вероятно, то, что вы ищете с точки зрения потокобезопасности и "привлекательности" при попытке использовать все в очереди:
for (YourObject obj = queue.poll(); obj != null; obj = queue.poll()) { }это гарантирует, что вы выходите, когда очередь пуста, и что вы продолжаете вытаскивать объекты из нее, пока она не пуста.
ConcurentLinkedQueue-это очень эффективная реализация без ожидания / блокировки (см. javadoc для справки), поэтому вам не только не нужно синхронизировать, но и очередь ничего не блокирует, таким образом, практически так же быстро, как несинхронизированный (не потокобезопасный).
просто используйте его, как вы бы не параллельной коллекции. Параллельные классы [Collection] обертывают обычные коллекции, так что вам не нужно думать о синхронизации доступа.
Edit: ConcurrentLinkedList на самом деле не просто оболочка, а скорее лучшая параллельная реализация. В любом случае, вам не нужно беспокоиться о синхронизации.
Comments