Внутренняя работа LinkedBlockingQueue - PullRequest
0 голосов
/ 05 июля 2018

Интересно, как обрабатывается следующий сценарий:

  • ScheduledThreadPool генерирует N элементов одновременно, каждую секунду.
  • Стремительный потребитель, который пытается создать пакеты из N объектов из очереди, вместо того, чтобы обрабатывать их один за другим.

Когда производитель просыпается и начинает помещать элементы в очередь (просто перенося объекты из списка), давайте предположим, что за один раз будет 100 элементов, потребитель сразу же проснется, опустошив очередь до того, как производитель установит 100 элементы?

Или я могу ожидать, что поток-поток будет бездействовать какое-то время дольше?

Ответы [ 2 ]

0 голосов
/ 06 июля 2018

Спасибо @Neerav Я сделал небольшой тест

private static void raceforIntegers() {
    BlockingDeque<Integer> q = new LinkedBlockingDeque<>();

    ScheduledExecutorService ex = Executors.newSingleThreadScheduledExecutor();
    // Delay producer 1 sec, so consumer always waits at 1st 
    ex.scheduleAtFixedRate(() -> {
                if (q.isEmpty()) {
                    Stream.iterate(0,  i -> ++i)
                            .limit(10)
                            .forEach(q::add);
                } else {
                    ex.shutdown();
                }
            }, 1L, 1L, TimeUnit.SECONDS);


    consumeIntegers(q);
}

private static void consumeIntegers(BlockingDeque<Integer> q) {
    int elememts = 30;
    StringBuilder sb = new StringBuilder();
    do {
        try {
            int n = q.take();
            int s = q.size();
            sb.append(s + ":::::" + n + "\n");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    } while (elememts-- > 0);
    System.out.println(sb);
}

выход

Size  Num
1:::::0
8:::::1
7:::::2
6:::::3
5:::::4
4:::::5
3:::::6
2:::::7
1:::::8
0:::::9

5:::::0
8:::::1
7:::::2
6:::::3
5:::::4
4:::::5
3:::::6
2:::::7
1:::::8
0:::::9

3:::::0
7:::::1
7:::::2
6:::::3
5:::::4
4:::::5
3:::::6
2:::::7
1:::::8
0:::::9
9:::::0
0 голосов
/ 06 июля 2018

LinkedBlockingQueue использует одиночную блокировку (ReentrantLock) для всей своей работы.

В вашем случае, когда вы говорите 100 элементов за раз, это означает, что метод put вызывается 100 раз. Метод put пытается получить блокировку перед вставкой. Так что вполне возможно, что Consumer Thread будет предоставлен шанс, и он может истощить очередь.

Кроме того, LBQ использует несправедливую блокировку, поэтому вероятность голодания вполне возможна.

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