Java

Asynchronous execution with ExecutorService. Runnable, Callable, Future, CountDownLatch.

ExecutorService

Build in API, which running of asynchronous tasks makes simple.

Create it with factory method from Executors class:

ExecutorService executor = Executors.newFixedThreadPool(5);

Assign a task in one of 3 ways:

  • submit(task) – provide Runnable or Callable task as an argument. Returns Future
 Future<Integer> future =
                executorService.submit(() -> {
                    System.out.println("Executing task 1");
                    return 1;
                });
        System.out.println("Executed task: " + future.get());
  • invokeAny(taskList) – provide collection of Callable tasks. Tries to execute all tasks, returns response from one of successfully executed.
     ExecutorService executorService = Executors.newFixedThreadPool(20);
        Integer res = executorService.invokeAny(Arrays.asList(() -> {
                    System.out.println("Executed 1");
                    return 1;
                },
                () -> {
                    System.out.println("Executed 2");
                    return 2;
                }));
        System.out.println("Returned Executed output: " + res);
  • invokeAll(taskList) – provide collection of Callable tasks. Executes all tasks and returns Future list with results of each of them.
        List<Future<Integer>> futures = executorService.invokeAll(Arrays.asList(() -> {
                    System.out.println("Executing task 1");
                    return 1;
                },
                () -> {
                    System.out.println("Executing task 2");
                    return 2;
                }));

        futures.forEach(f -> {
            try {
                System.out.println("Executed: " + f.get());
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        });

Runnable

    • Functional interface with single method run().
    • Does not accept any parameters and reurns nothing.
    • Suitable for any task when don’t need an outcome. Example – event logging, sending emails.
public interface Runnable {
    public void run();
}

Callable

  • Functional interface with single method call().
  • Does not accept any parameters and returns a generic value.
  • Suitable for asynchronous tasks when need an outcome. Example – status of whether an action was sucessfull or even return some fetched data from external datasource.
public interface Callable<V> {
    V call() throws Exception;
}

Future

Represents result of asynchronously executed task. When submitting Callable task for Executor service we immediately get a Future object. Its does not hold a value while asynchronous process is not done.

CountDownLatch

Used for controlling completion of asynchronous tasks. Basically we are counting each completed task until specified number. When get it, know that all of them are completed and we can use outcome for further processing.

        List<String> contentList = new ArrayList<>();
        ExecutorService executorService = Executors.newFixedThreadPool(20);
        CountDownLatch latch = new CountDownLatch(2);

        Future<String> task1 = executorService.submit(() -> {
            try {
                Thread.sleep(2000);
            } catch (Exception e) {
            }
            contentList.add("Content from task1");
            latch.countDown();
            return "done";
        });
        Future<String> task2 = executorService.submit(() -> {
            contentList.add("Content from task2");
            latch.countDown();
            return "done";
        });
        latch.await(1000, TimeUnit.MILLISECONDS);
        System.out.println(contentList);

About Danas Tarnauskas