TheOnlyKiller
TheOnlyKiller

Reputation: 21

How to call same function in parallel with executor service in JAVA?

I am new to concurrency and threading in java and I have this following scenario -

Function1(fetches next task from a queue and calls function2 with task) then Function2(calls Function Run to run this task) then Run(function run is submiting task using executor service which has a fixed thread pool and code is like below)

    ExecutorService exeService = Executors.newFixedThreadPool(3);
         private void run(Task task){
                    Abstract batchExecutor = getBatchExecutor(param1,param2, param3, param4, task);
                    Future<Void> future = exeService.submit(batchExecutor);
                    while (!future.isDone()) {
                        if (isStopRequested.get()) {
                            try {
                                future.get(5, TimeUnit.MINUTES);
                                } catch (TimeoutException e) {
                            e.printStackTrace();
                        }
                        throw new InterruptedException("message");
                    }
                            Thread.sleep(3000);
                    }
                        future.get();
                   Map<String, Result> submittedObjects = batchExecutor.getSubmittedObjects();
                   storeSubmittedObjects(submittedObjects);
        }

My problem is even after declaring a thread pool also tasks are still running in sequential way. How can I make it parallel so that as soon as there is another call to the run it should use free thread from pool and submit the task?

There is no return type for all these functions.

Upvotes: 0

Views: 1020

Answers (1)

DuncG
DuncG

Reputation: 15186

The run(Task task) method contains future.get(); at the end: this means that your current thread will block until the submitted operation is completed. Hence if you make 3x calls to run(Task task) in same thread then all 3 tasks will execute sequentially not in parallel.

How to handle this properly rather depends on how you structure your application. If you don't submit huge number of tasks you could return the future from the method:

private Future<Void> run(Runnable task){
    Abstract batchExecutor = getBatchExecutor(param1,param2, param3, param4, task);
    return exeService.submit(batchExecutor);
}

Then scan the results later:

ArrayList<Future<Void>> pending = new ArrayList<>();
pending.add(run(task1));
pending.add(run(task2));
pending.add(run(task3));
// ...

// clean up background tasks
for (Future<?> fut : pending)
{
    fut.get();
}

Note that if you don't use results of the future, you can omit collecting pending and the above loop. Just ensure that your app closes the executor queue after all tasks are completed:

exeService.shutdown();
exeService.awaitTermination(365, TimeUnit.DAYS);

If you need to perform post processing after each task, your run(Task) method should change to use exeService.submit(Callable<SomeResult - such as Abstract>) and return Future<SomeResult> so that you can perform follow on actions in the calling thread later.

Upvotes: 2

Related Questions