SynchronousQueue
- это очень особый вид очереди - он реализует подход рандеву (производитель ждет, пока потребитель готов, потребитель ждет, пока производитель готов) за интерфейсом Queue
.
Поэтому он может понадобиться только в особых случаях, когда вам нужна конкретная семантика, например, Однопоточность задачи без постановки в очередь дальнейших запросов .
Другой причиной использования SynchronousQueue
является производительность. Реализация SynchronousQueue
кажется сильно оптимизированной, поэтому если вам не нужно ничего, кроме точки встречи (как в случае Executors.newCachedThreadPool()
, где потребители создаются «по требованию», так что элементы очереди не ' т), вы можете получить прирост производительности, используя SynchronousQueue
.
Простой синтетический тест показывает, что в простом сценарии с одним производителем и одним потребителем на двухъядерной машине пропускная способность SynchronousQueue
в ~ 20 раз выше, чем пропускная способность LinkedBlockingQueue
и ArrayBlockingQueue
с длиной очереди = 1. Когда очередь длина увеличивается, их пропускная способность увеличивается и почти достигает пропускной способности SynchronousQueue
. Это означает, что SynchronousQueue
имеет низкие издержки синхронизации на многоядерных машинах по сравнению с другими очередями. Но опять же, это имеет значение только в определенных обстоятельствах, когда вам нужна точка встречи, замаскированная под Queue
.
EDIT:
Вот тест:
public class Test {
static ExecutorService e = Executors.newFixedThreadPool(2);
static int N = 1000000;
public static void main(String[] args) throws Exception {
for (int i = 0; i < 10; i++) {
int length = (i == 0) ? 1 : i * 5;
System.out.print(length + "\t");
System.out.print(doTest(new LinkedBlockingQueue<Integer>(length), N) + "\t");
System.out.print(doTest(new ArrayBlockingQueue<Integer>(length), N) + "\t");
System.out.print(doTest(new SynchronousQueue<Integer>(), N));
System.out.println();
}
e.shutdown();
}
private static long doTest(final BlockingQueue<Integer> q, final int n) throws Exception {
long t = System.nanoTime();
e.submit(new Runnable() {
public void run() {
for (int i = 0; i < n; i++)
try { q.put(i); } catch (InterruptedException ex) {}
}
});
Long r = e.submit(new Callable<Long>() {
public Long call() {
long sum = 0;
for (int i = 0; i < n; i++)
try { sum += q.take(); } catch (InterruptedException ex) {}
return sum;
}
}).get();
t = System.nanoTime() - t;
return (long)(1000000000.0 * N / t); // Throughput, items/sec
}
}
А вот результат на моей машине: