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 шт):

Автор решения: Roman Konoval

Проблема в том, что 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);
                }
            }
        ...
    }

→ Ссылка
Автор решения: Artem

После долгого времени поисков и размышлений, достижения отчаяния и его преодоления ... решил проблему добавлением аннотации @Scope("prototype") на класс треда.

→ Ссылка