Выполнить метод с возвращаемым типом и входным параметром параллельно

#java #spring #multithreading #spring-boot #parallel-processing

#java #spring #многопоточность #весенняя загрузка #параллельная обработка

Вопрос:

У меня есть приведенный ниже код. Я хочу выполнять m3() параллельно 3 потоками, поскольку я выполняю m1 и m2.

Как я могу этого добиться. Я использую Spring Boot и java 8. Возможно ли выполнить m3() с помощью службы исполнителя.

 @Service
class Main {
    @Autowired
    Private Other other;
    ExecutorService executorService = Executors.newFixedThreadPool(3);
   
    void test_method() {
        for (int i = 0; i < 201; i  ) {
            executorService.submit(() -> other.m1()); // works fine as expected 
            executorService.submit(() -> other.m2()); // works fine as expected 
            executorService.submit(() -> other.m3(i)); // compilation error  as expected
    }
}
  

Ошибка

Локальная переменная, определенная i во включающей области, должна быть окончательной или фактически окончательной

Методы приведены ниже

 @Service
class Other {
    void m1() {
    }
    
    String m2() {
        return "Hello";
    }
 
    int m3(int n) {
        return n;
    }
}
  

Комментарии:

1. В чем ошибка?

2. Local variable i defined in an enclosing scope must be final or effectively final

Ответ №1:

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

  • Конечная переменная — это та, которая создается только один раз.
  • Эффективно-конечная переменная — это та, значение которой никогда не изменяется после инициализации.

Одним из возможных обходных путей является использование IntStream.range IntStream.forEach методов и:

 IntStream.range(0, 201).forEach(i -> {
    executorService.submit(() -> other.m1());
    executorService.submit(() -> other.m2());
    executorService.submit(() -> other.m3(i));
});
  

Комментарии:

1. Спасибо. Но ваш метод будет работать для int. Предположим, я передавал какой-то пользовательский Pojo, такой как MyObject, в m3(), тогда как бы я это сделал? Есть какой-нибудь элегантный способ сделать это?

2. Зачарованный цикл работает: for (Pojo pojo: list) { executorService.submit(() -> other.m3(pojo)); }

Ответ №2:

попробуйте это:

 void test_method() {
    for (int i = 0; i < 201; i  ) {
        executorService.submit(other::m1);
        executorService.submit(other::m2);
        final int i1 = i;
        executorService.submit(() -> other.m3(i1));        
    }
}
  

Комментарии:

1. я постараюсь, спасибо. И я решил проблему , используя создание контейнерного класса для int final MyContainer myContainer = new MyContainer(i); myContainer.getIntValue() . Но есть ли у вас какое-нибудь элегантное решение для выполнения m3() параллельно с ot без ExecutorService

2. и ваше и мое решение почти одинаковы. Но предположим, что я передавал какой-то пользовательский класс Pojo в m3

3. @PaleBlueDot выполнить m3() параллельно с чем? он уже выполнен с максимально возможным логическим параллелизмом. Для достижения максимального физического параллелизма используйте ExecutorService ExecutorService = Executors.newFixedThreadPool(Runtime.getRuntime().Available Processors());