Запуск функций в параллельной Java

Я пытаюсь запустить две функции параллельно в Java, но у меня есть определенные критерии, и я не знаю, соблюдаются ли они. Ниже приведен код, который у меня есть. Код под службой исполнителя находится в основной функции, над ним есть какой-то другой код, который не имеет отношения к вопросу, поэтому я решил сократить код для удобства чтения.

private static final ExecutorService executorService = Executors.newFixedThreadPool(2);

            if (!weekly || rowData.get("M/W").equals("W")) {
            if (callData != null) {
                Future<?> bidPriceFuture = executorService.submit(() -> {
                    getBidPrice(rowData.get("Symbol"), callData, premiumC, percentMinC, "Call",
                            rowData.get("Call EPR").equals("#N/A") ? 0 : Double.parseDouble(rowData.get("Call EPR")), rowData);
                });

                Future<?> updateVerticalsFuture = executorService.submit(() -> {
                    updateVerticals(rowData.get("Symbol"), callData);
                });

                bidPriceFuture.get();
                updateVerticalsFuture.get();
            }
            if (putData != null) {
                System.out.println("Running the Put Stuff");
                Future<?> putFuture = executorService.submit(() -> {
                    getBidPrice(rowData.get("Symbol"), putData, premiumP, percentMinP, "Put",
                            rowData.get("Put EPR").equals("#N/A") ? 0 : Double.parseDouble(rowData.get("Put EPR")), rowData);
                });

                Future<?> updateVerticalPut = executorService.submit(() -> {
                    updateVerticals(rowData.get("Symbol"), putData);
                });

                putFuture.get();
                updateVerticalPut.get();
            }

Подводя итог, я хочу запустить getBidPrice и updateVerticalsFuture параллельно для первого оператора if и второго оператора if. Однако из-за ограничений API я хочу запустить процесс для второго оператора if только тогда, когда оба процесса в первом операторе завершились. Моим первым решением этой проблемы было добавление .get() к объекту Future, но я думаю, что это останавливает реальный параллелизм, потому что если я вызываю bidPriceFuture.get(), то я не знаю, работает ли другая функция в фон. Учитывая мои критерии, я был бы признателен за любые рекомендации о том, как я могу запускать обе эти функции параллельно.

Все в порядке, у вас есть пул из 2 потоков и вы отправляете 2 задачи. Они выполняются параллельно, и два get()-s гарантируют, что оба они завершатся к тому времени, когда вы перейдете к следующему if.

tevemadar 29.07.2024 00:43

Исправьте отступы вашего кода.

Basil Bourque 29.07.2024 00:47

Публикуя здесь, придумайте упрощенный сценарий с минимумом кода. Выгружать реальный код с ненужными деталями, по меньшей мере, бесполезно.

Basil Bourque 29.07.2024 00:49
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
3
84
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

ExecutorService это Autocloseable

Вы сказали:

Я хочу запустить процесс для второго оператора if только тогда, когда оба процесса в первом операторе завершились.

Воспользуйтесь тем, что ExecutorService является AutoCloseable . Это означает, что вы можете использовать синтаксис try-with-resources для автоматического закрытия службы-исполнителя после завершения задач.

if ( firstCondition ) 
{
    Collection< Future<Whatever> > futures = List.of() ;
    try 
    (
        ExecutorService executorService = Executors.newVirtualThreadPerTaskExecutor() ;
    ) 
    {
        Future<Whatever> x = executorService.submit( someTask ); 
        Future<Whatever> y = executorService.submit( otherTask ); 
        futures = List.of( x , y ) ;
    }  
    // Flow of control blocks here until submitted tasks complete.
    for ( Future<Whatever> future : futures ) 
    { 
        …  // Call `Future#get` here to get result of each future. 
    }
}

if ( secondCondition ) 
{
    … // For your second set of tasks, use similar code as above.
}

Вы сказали:

добавьте .get() к объекту Future, но я думаю, что это останавливает реальный параллелизм

Вызов Future#get блокирует текущий поток (поток, выполняющий вызов Future#get). На этом поток управления текущим потоком останавливается до тех пор, пока задача не завершится и не вернет результат. Тем временем другие фоновые потоки продолжают выполняться. Сюда входят и другие задачи, отправленные службе исполнителя (если они многопоточные). Если у службы-исполнителя есть доступные потоки, все отправленные задачи продолжают обрабатываться независимо от того, какой вызов вы сделали или не сделали Future#get. Вызов Future#get означает «остановить этот поток здесь и подождать, пока эта фоновая задача в другом потоке не будет выполнена и не будет готова с результатом». Вызов Future#get не влияет на задачу или ее фоновый поток. Подробнее см. Ответ Берта Ф..


В будущем лучший подход будет использовать Структурированный параллелизм.

Ответ принят как подходящий

Моим первым решением этой проблемы было добавление .get() к объекту Future, но я думаю, что это останавливает реальный параллелизм, потому что если я вызываю bidPriceFuture.get(), то я не знаю, работает ли другая функция в фон.

Я думаю, вы путаете поведение .submit() и .get(). У вас есть 2 потока и вы отправили две задачи в фиксированный двухпоточный рабочий пул — есть все основания полагать, что задачи выполняются параллельно. Задачи/потоки не «ожидают» начала выполнения вызова .get().

Если вы хотите это подтвердить, вам нужна видимость вашей программы, например. добавив ведение журнала или System.out.println(), чтобы отслеживать выполнение вашей программы и наблюдать за ее поведением. Но даже в этом случае, если ваша первая задача выполняется очень быстро, она может завершиться еще до того, как начнется вторая.

Другие вопросы по теме