ExecutorService. Все запущеные треды начинают выполнять задачу последнего
Столкнулся с такой проблемой: У меня в базе есть список различных слов на одном языке. Я пытаюсь перевести эти слова на несколько других языков.
@Component
public class WordsProcessingSchedule implements Runnable {
private final ExecutorService executorService = Executors.newFixedThreadPool(Util.wordsProcessingThreads);
@Autowired
ApplicationContext context;
@Autowired
TranslationRequestRepository translationRequestRepository;
@Override
public void run(){
List<TranslationRequest> translationRequests = translationRequestRepository.getActualWordsRequests();
int threatQty = translationRequests.size();;
CountDownLatch latch = new CountDownLatch(threatQty);
if(threatQty > 0){
for(int i = 0; i < threatQty; i++) {
WordsTranslateProcessing wordsTranslateProcessing = context.getBean(WordsTranslateProcessing.class);
wordsTranslateProcessing.setThreadId(i);
wordsTranslateProcessing.setCountDownLatch(latch);
wordsTranslateProcessing.setTranslationRequest(translationRequests.get(i));
executorService.execute(wordsTranslateProcessing);
}
try {
latch.await();
} catch (InterruptedException e) {
System.out.println(e.getMessage());
}
}
else {
latch.countDown();
}
}
В коде, я получаю все нужные языки в список translationRequests. Потом поочередно задаю каждому треду нужный язык. В debug видно, что каждый тред получает нужный язык. Но, после выхода из цикла, все треды начинают переводить слова на язык назначенный последнему треду. Пока не могу определить, что я делаю не так. Заранее спасибо тому, кто поможет понять в чем ошибка.
Ответы (2 шт):
Проблема в том, что context.getBean(WordsTranslateProcessing.class) всегда возвращает один и тот же объект, так что вы в цикле постоянно ему меняете значение языка.
Избавьтесь от состояния в WordsTranslateProcessing, т.е. не храните там язык в виде поля, а передавайте его в метод этого класса. Тогда один класс сможет обрабатывать несколько потоков одновременно:
class WordsTranslateProcessing {
public void translate(TranslationRequest translationRequest, CountDownLatch latch, int threadId) {
// тут обрабатываем не сохраняя параметры в поля объекта
}
}
@Component
public class WordsProcessingSchedule implements Runnable {
private final ExecutorService executorService = Executors.newFixedThreadPool(Util.wordsProcessingThreads);
@Autowired
ApplicationContext context;
@Autowired
TranslationRequestRepository translationRequestRepository;
@Autowired
WordsTranslateProcessing wordsTranslateProcessing;
@Override
public void run(){
...
if(threatQty > 0){
for(int i = 0; i < threatQty; i++) {
executorService.execute(() -> {
wordsTranslateProcessing.translate(
translationRequests.get(i), latch, i);
}
}
...
}
После долгого времени поисков и размышлений, достижения отчаяния и его преодоления ... решил проблему добавлением аннотации @Scope("prototype") на класс треда.