Rishab
Rishab

Reputation: 345

Running functions in Parallel Java

I am trying to run two functions in parallel in Java, but I have a specific criteria which I don't know whether it is being met. Below is the code which I have. The code below the executor service is in the main function, there is just some other code above it, which is not relevant to the question, so i decided to reduce the code for readability.

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();
            }

To summarize, I want to run both the getBidPrice and the updateVerticalsFuture in parallel for the first if statement and the second if statement. However, due to API limits, I only want to start the process for the second if statement when both the processes in the first statement have finished. My first fix for this was to add the .get() to the Future object, but I think that is stopping the actual parallelism because if I call bidPriceFuture.get(), then I don't know if the other function is running in the background. Given the criteria I have, I would appreciate any recommendations on how I can run both these functions in true parallel.

Upvotes: 1

Views: 134

Answers (2)

Basil Bourque
Basil Bourque

Reputation: 339837

ExecutorService is Autocloseable

You said:

I only want to start the process for the second if statement when both the processes in the first statement have finished

Take advantage of the fact that ExecutorService is AutoCloseable. This means you can use try-with-resources syntax to automatically close the executor service after the tasks complete.

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.
}

You said:

add the .get() to the Future object, but I think that is stopping the actual parallelism

The call to Future#get blocks the current thread (the thread making the Future#get call). The flow-of-control of the current thread stops there until that task completes and returns its result. Meanwhile other background threads continue to execute. This includes other tasks submitted to the executer service (if multi-threaded). If the executor service has threads available, all submitted tasks continue processing regardless of any call you may or may not have made to Future#get. Calling Future#get means “stop this thread here to wait until that background task on another thread is done and ready with its result”. Calling Future#get has no effect on the task or its background thread. See Answer by Bert F for details.


In the future, a better approach will use Structured Concurrency.

Upvotes: 2

Bert F
Bert F

Reputation: 87593

My first fix for this was to add the .get() to the Future object, but I think that is stopping the actual parallelism because if I call bidPriceFuture.get(), then I don't know if the other function is running in the background.

I think you are confusing the behaviors of the .submit() and .get(). You have 2 threads and submitted two tasks to the fixed 2-thread worker pool - there is every reason to believe that the tasks are running in parallel. The tasks/threads don't "wait" for the .get() call to start executing.

If you want to confirm this, you need visibility into your program, e.g. by adding logging or System.out.println() to trace the execution of your program to observe its behavior. But even then, if your first task is very fast, it may complete before the 2nd one even starts.

Upvotes: 2

Related Questions