1

Я пытаюсь создать многопоточное приложение в Java с использованием пулов потоков ExecutorService. Приложение в основном запрашивает стороннюю службу для данных о данном ключевом слове. Поскольку у меня много ключевых слов, и каждый запрос занимает некоторое время, чтобы сгенерировать, я хотел бы запросить службу параллельно. Запросы выполняются через объект ServiceHandler, который выполняет проверку подлинности и анализирует результаты.Доля объектов между задачами в пуле потоков, но не между потоками в Java

В моей первоначальной реализации я создаю новый Callable для каждого ключевого слова и создаю новый объект ServiceHandler для запроса службы. По какой-то причине это выполняется быстрее, чем совместное использование одного объекта ServiceHandler во всех Callable. Однако, с большими наборами входных данных, я сталкиваюсь с проблемами памяти, потому что он создает новые объекты для каждого ключевого слова ввода.

Есть ли способ использовать ExecutorService, но только создать отдельный экземпляр ServiceHandler для каждого рабочего потока? Например, если у меня есть 1000 ключевых слов и фиксированный пул из 20 потоков, я хочу создать только один ServiceHandler для каждого потока (всего 20), в то же время имея по одному Callable для каждого ключевого слова (всего 1000).

Я попытался добавить статический объект ThreadLocal к каждому вызываемому объекту, который возвращает новый ServiceHandler в свой initialValue(), но создается впечатление, что создается только один ServiceHandler? Я могу опубликовать свой код для этого, но я даже не уверен, что это правильный подход.

ответ

1

Да, есть способ создать только один экземпляр объекта в потоке, вы должны использовать ThreadLocal<ServiceHandler> и объявить его как статическое поле. Это создало бы только один экземпляр объекта для потока. Вы можете проверить http://docs.oracle.com/javase/6/docs/api/java/lang/ThreadLocal.html это для официальной документации.

+0

Я попробовал это и добавил новую статическую изменчивую переменную instanceCount в ServiceHandler. Когда я увеличиваю эту переменную в конструкторе ServiceHandler и распечатываю ее, я всегда получаю 1, что похоже на то, что я создаю только один экземпляр? – Yiling

0

Я думаю, что это проблема производителя-потребителя. У вас есть BlockingQueue, который может содержать столько ключевых слов, сколько вам нравится, и пул из 20 потоков потребителей/сервисов.

Нити службы работают так:

while (true) { 
    Keyword k = queue.pop(); 
    process(k); 
} 

Ваш продюсер поток просто заполняет очередь с ключевыми словами, которые вы хотите обработать и один из потоков услуг будет заботиться о нем.

+0

В основном это, но я хотел бы использовать ExecutorService, потому что он позволяет мне создать основной класс, который читает на входе, создает пул потоков, а затем записывает результат, как только результаты возвращаются из службы. Если я создаю отдельные потоки обслуживания, мне нужно реализовать собственную инфраструктуру типа ExecutorService. – Yiling

0

Я выясняю, какова моя конкретная проблема. Правильное решение - использовать объект ThreadLocal, но проблема с моей реализацией заключалась в том, что я вызывал метод ThreadLocal.get(), когда я создавал каждую Callable. Поскольку строительство происходит в основной теме, а не в рабочих потоках ExecutorService, я всегда получал тот же экземпляр ServiceHandler, который делал его похожим на singleton.

Как только я перевел вызов метода get() на метод callable call(), произойдет правильное выполнение.

+0

, так что теперь вы можете отметить один из ответов как правильный – Desert