Executor Framework

  • Primary abstraction for task execution is Executor in Executor Framework instead of Thread
  • Supports launching new tasks via execute() using Runnable only
public interface Executor {
    void execute(Runnable command);
}

ExecutorService

  • sub-interface of Executor
  • adds lifecycle methods to Executor
  • Supports launching task via submit() using Runnable or Callable
public interface ExecutorService extends Executor {
    Future<?> submit(Runnable task);
    Future<T> submit(Callable<T> task);
 
    void shutDown(); // graceful shutdown
    // ...other methods
}
  • ExecutorService has three states:
    • running
    • shutting down
    • terminated
  • Implementations:
    • ThreadPoolExecutor
    • ThreadPerTaskExecutor
    • ForkJoinPool
    • ScheduledThreadPoolExecutor

ScheduledExecutorService

  • sub-interface of ExecutorService
  • supports future and/or periodic execution of tasks to ExecutorService

Executors

  • Utility class to create Executor
  • Executors with thread pool
    • newFixedThreadPool(): ExecutorService
    • newCachedThreadPool(): ExecutorService
    • newSingleThreadExecutor(): ExecutorService
    • newScheduledThreadPool(): ScheduledExecutorService

Resource Pooling

  • Pre-create and store multiple instances of expensive/bottleneck prone components
  • Components are immediately ready for use
  • examples:
    • database connections
    • messaging queue connections
    • network connections
    • Thread pools
  • Database connection pooling is a way to reduce the cost of opening and closing connections by maintaining a “pool” of open connections that can be passed from database operation to database operation as needed.
    • In the case of database each connection need credentials, url, port to establish
    • In spring boot/JDBC HikariCP connection pool is recommended

Thread pool

  • A thread does not start unless explicitly asked to do so.
  • A thread pool consists of worker threads which can be reused to execute tasks
  • when a new task is submitted to be executed, thread pool can be used to reuse the threads
  • Helpful when creating a thread is more costly than executing the thread

Result Bearing Tasks

  • Runnable (Functional Interface) is limiting abstraction as run() cannot return a value or throw exceptions
  • Callable (Functional Interface) can return value + throw exceptions
  • Future has state + lifecycle methods + throw exceptions

ExecutorCompletionService

  • Uses ExecutorService + BlockingQueue

ForkJoinPool

  • implementation of the ExecutorService
  • helps you take advantage of multiple processors
  • Based on ForkJoinTask
  • The fork/join framework allows parallelizing recursive algorithms.
  • The main problem with parallelizing recursion using something like ThreadPoolExecutor is that you may quickly run out of threads because each recursive step would require its own thread, while the threads up the stack would be idle and waiting
  • Performs work-stealing algorithm, Worker threads that run out of things to do can steal tasks from other threads that are still busy
  • Examples:
    • Arrays.parallelSort()
    • Collection#parallelStream()