Я бы предложил использовать LinkedBlockingQueue
вместо CopyOnWriteArrayList
в качестве значения карты. С COWAL добавление становится все дороже, поэтому добавление N элементов приводит к производительности N ^ 2. LBQ сложение O (1). Кроме того, LBQ имеет drainTo
, который можно эффективно использовать здесь. Вы могли бы сделать это:
final Map<String, Queue<Update>> updatesPerId = new ConcurrentHashMap<>();
Производитель:
updatesPerId.computeIfAbsent(id, LinkedBlockingQueue::new).add(update);
Потребитель:
updatesPerId.forEach((id, queue) -> {
List<Update> updates = new ArrayList<>();
queue.drainTo(updates);
processUpdates(id, updates);
});
Это несколько отличается от того, что вы предложили. Этот метод обрабатывает обновления для каждого идентификатора, но позволяет производителям продолжать добавлять обновления на карту, пока это происходит. Это оставляет записи карты и очереди на карте для каждого идентификатора. Если идентификаторы в конечном итоге будут многократно использоваться, количество записей на карте увеличится до максимальной отметки.
Если новые идентификаторы постоянно появляются, а старые идентификаторы становятся неиспользуемыми, карта будет постоянно расти, что, вероятно, не то, что вам нужно. Если это так, вы можете использовать эту технику в ответе Энди Тернера .
Если потребителю действительно нужно сделать снимок и очистить всю карту, я думаю, что вы должны использовать блокировку, которую вы хотели избежать.