Я пытаюсь запустить две функции параллельно в 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(), то я не знаю, работает ли другая функция в фон. Учитывая мои критерии, я был бы признателен за любые рекомендации о том, как я могу запускать обе эти функции параллельно.
Исправьте отступы вашего кода.
Публикуя здесь, придумайте упрощенный сценарий с минимумом кода. Выгружать реальный код с ненужными деталями, по меньшей мере, бесполезно.
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(), чтобы отслеживать выполнение вашей программы и наблюдать за ее поведением. Но даже в этом случае, если ваша первая задача выполняется очень быстро, она может завершиться еще до того, как начнется вторая.
Все в порядке, у вас есть пул из 2 потоков и вы отправляете 2 задачи. Они выполняются параллельно, и два
get()
-s гарантируют, что оба они завершатся к тому времени, когда вы перейдете к следующемуif
.