Я использую ThreadPoolTaskExecutor (of spring) для асинхронного выполнения некоторых задач.
Требуемая задача загрузит какой-то объект из внешней БД в мою системную память. Я использую максимальный размер пула потоков 10 и максимальный размер очереди 100.
Предположим, что все 10 потоков заняты получением объектов из моей БД и создана задача, она отправится в очередь. Теперь создается другая задача, которая должна получить тот же объект (тот же ключ в БД) из БД, он также перейдет в очередь (при условии, что все 10 потоков все еще заняты).
Таким образом, моя очередь может легко заполниться дублированными задачами, которые будут выполняться по очереди, а я не хочу, чтобы это произошло.
Я думал, что решение должно быть в виде уникальной коллекции, которая служит очередью пула потоков. Под капотом ThreadPoolTaskExecutor используется LinkedBlockingQueue, который не обеспечивает уникальности.
Я придумал несколько возможных решений, но ни одно меня не удовлетворило:
- Использование ThreadPoolExecutor вместо ThreadPoolTaskExecutor. ThreadPoolExecutor предоставляет конструктор, который позволяет мне определять тип очереди пула потоков, но ему необходимо реализовать интерфейс BlockingQueue. Не нашел реализации, сохраняющей уникальность.
Это побудило меня попытаться расширить LinkedBlockingQueue и переопределите добавить:
public boolean add(E e)
if(!this.contains(e)) {
return super.add(e);
} else {
return false;
}
}
Но насколько я могу судить, это приведет к значительному снижению производительности, поскольку метод contains
ограничен O (n) - плохая идея.
Что могло решить мою проблему? Я стремлюсь к хорошей производительности (в случае компромисса между памятью и производительностью я не против отказаться от памяти ради производительности).