Когда я должен использовать SynchronousQueue - PullRequest
50 голосов
/ 21 декабря 2011
new SynchronousQueue()
new LinkedBlockingQueue(1)

В чем разница? Когда я должен использовать SynchronousQueue против LinkedBlockingQueue с емкостью 1?

Ответы [ 5 ]

48 голосов
/ 21 декабря 2011

SynchronousQueue - это скорее передача обслуживания, тогда как LinkedBlockingQueue позволяет только один элемент. Разница в том, что вызов put () для SynchronousQueue не вернет до тех пор, пока не произойдет соответствующий вызов take (), но с LinkedBlockingQueue размера 1 вызов put () (в пустую очередь) вернется немедленно.

Не могу сказать, что когда-либо сам использовал SynchronousQueue, но это метод BlockingQueue по умолчанию, используемый для методов Executors.newCachedThreadPool(). По сути, это реализация BlockingQueue, когда вы действительно не хотите очереди (вы не хотите поддерживать ожидающие данные).

9 голосов
/ 21 декабря 2011

Насколько я понимаю, код выше делает то же самое.

Нет, код совсем не тот.

Sync.Q.Требуется официант (ы) для предложения, чтобы преуспеть.LBQ сохранит предмет, и предложение будет немедленно завершено, даже если официанта нет.

SyncQ полезен для передачи задач.Представьте, что у вас есть список с ожидающей задачей и 3 доступных потока, ожидающих в очереди, попробуйте offer() с 1/4 списка, если не принято, поток может выполнить задачу самостоятельно.[последний 1/4 должен обрабатываться текущим потоком, если вам интересно, почему 1/4, а не 1/3]

Подумайте о попытке передать задачу работнику, если у вас нет ни одного доступноговозможность выполнить задачу самостоятельно (или сгенерировать исключение).Напротив, с LBQ, оставление задачи в очереди не гарантирует выполнения.

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

6 голосов
/ 01 ноября 2013

Одной из причин использования SynchronousQueue является повышение производительности приложений. Если вам нужно переключиться между потоками, вам понадобится некоторый объект синхронизации. Если вы можете удовлетворить условия, необходимые для его использования, SynchronousQueue - самый быстрый объект синхронизации, который я нашел. Другие согласны. См .: Реализация BlockingQueue: чем отличаются SynchronousQueue от LinkedBlockingQueue

1 голос
/ 18 октября 2018

[Просто пытаюсь выразить это (возможно) более ясными словами.]

Я полагаю, что SynchronousQueue API документы очень четко заявляют:

  1. Очередь блокировки, в которой каждая операция вставки должна ожидать соответствующей операции удаления другим потоком, и наоборот.
  2. Синхронная очередь не имеет внутренней емкости, даже емкости одной. Вы не можете заглянуть в синхронную очередь, потому что элемент присутствует только при попытке удалить его; вы не можете вставить элемент (используя любой метод), если другой поток не пытается удалить его; Вы не можете повторять, так как нечего повторять.
  3. Голова очереди - это элемент, который пытается добавить первый поток вставки в очередь; если такого потока в очереди нет, элемент для удаления недоступен и poll() вернет null.

И BlockingQueue Документы API :

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

Таким образом, разница очевидна и несколько критична, особенно 3-й пункт ниже:

  1. Если при извлечении из BlockingQueue очередь пуста, операционный блок пока не вставлен новый элемент. Кроме того, если очередь заполнена при вставке в BlockingQueue, операция будет блокироваться до тех пор, пока элемент не будет удален из очереди и не будет выделено место для новой очереди. Однако обратите внимание, что в SynchronousQueue, поскольку операция блокируется для противоположной операции (вставка и удаление противоположны друг другу), чтобы происходить в другом потоке. Таким образом, в отличие от BlockingQueue, блокировка зависит от наличия операции, а не от наличия или отсутствия элемента .
  2. Поскольку блокировка зависит от существования противоположной операции, элемент никогда не вставляется в очередь. Вот почему второй пункт: « Синхронная очередь не имеет внутренней емкости, даже емкости одной. »
  3. Как следствие, peek() всегда возвращает null (опять же, проверьте API doc ), а iterator() возвращает пустой итератор, в котором hasNext() всегда возвращает false. ( API doc ). Однако обратите внимание, что метод poll() аккуратно извлекает и удаляет заголовок этой очереди, если другой поток в настоящее время делает элемент доступным, и если такой поток не существует, он возвращает null. ( API doc )

Наконец, небольшая заметка, оба класса SynchronousQueue и LinkedBlockingQueue реализуют интерфейс BlockingQueue.

0 голосов
/ 13 января 2015

SynchronousQueue работает аналогичным образом со следующими основными отличиями: 1) Размер SynchronousQueue равен 0 2) метод put () будет вставлять элемент только в том случае, если метод take () сможет извлечь этот элемент из очереди в один и тот же момент, т. Е. Элемент не может быть вставлен, если для вызова take () потребителя потребуется некоторое время, чтобы потреблять его.

SynchronousQueue - вставлять только тогда, когда кто-то сам получит его в этот момент.

...