Origins

In the JDK, Executors were provided for creating custom thread pool objects called ExecutorService, but considering the numerous concepts within the thread pool, different combinations of these concepts were needed to achieve flexible threading management strategies, which could not be satisfied by using Executors alone, hence the construction of ExecutorBuilder.

Concepts

  • corePoolSize: Initial pool size
  • maxPoolSize: Maximum pool size (maximum number of threads allowed to execute simultaneously)
  • workQueue: Queue for storing unexecuted threads
  • handler: Exception handler when a thread is blocked, where thread blocking occurs when the thread pool and waiting queue are full and cannot process any more threads

Thread Pool Strategy for Handling Threads

  1. If the number of tasks in the pool is less than corePoolSize, execute immediately
  2. If the number of tasks in the pool is greater than corePoolSize, place them in the queue to wait
  3. If the queue is full, create a new thread and execute immediately
  4. If there are more executing threads than maxPoolSize, trigger an exception from the handler (RejectedExecutionHandler)

Work Queue Thread Pool Strategy

  • SynchronousQueue: It submits tasks directly to threads without maintaining them. When there are fewer running threads than maxPoolSize, new threads are created, otherwise an exception strategy is triggered.
  • LinkedBlockingQueue: The default unbounded queue, tasks are always placed in this queue when there are more running threads than corePoolSize, at which point maxPoolSize is ineffective. When a LinkedBlockingQueue object is constructed with parameters, it becomes a bounded queue. When the queue is full and there are fewer running threads than maxPoolSize, new threads are created, otherwise an exception strategy is triggered.
  • ArrayBlockingQueue: Bounded queue that is more conducive to controlling queue size. When the queue is full and there are fewer running threads than maxPoolSize, new threads are created, otherwise an exception strategy is triggered.

Usage

  1. Default Thread Pool

Strategy:

  • Initial threads are set to the size specified by corePoolSize
  • No maximum thread limit is imposed
  • The default queue used is LinkedBlockingQueue with a default size of 1024 (maximum waiting capacity of 1024)
  • Tasks that cannot be executed immediately due to insufficient threads are placed in the queue, and an exception is thrown when the queue becomes full.
ExecutorService executor = ExecutorBuilder builder = ExecutorBuilder.create()..build();
  1. Single-Threaded Thread Pool
  • Initial threads number 1
  • Maximum threads number 1
  • The default queue used is LinkedBlockingQueue with a default size of 1024
  • Only one thread is allowed to work at a time, and any additional tasks are placed in the queue to wait. An exception is thrown if the waiting capacity exceeds 1024.
ExecutorService executor = ExecutorBuilder.create()//
 .setCorePoolSize(1)//
 .setMaxPoolSize(1)//
 .setKeepAliveTime(0)//
 .build();
  1. Thread Pool with Additional Options
  • Initial threads number 5
  • Maximum threads number 10
  • The queue used is LinkedBlockingQueue with a maximum waiting capacity of 100
ExecutorService executor = ExecutorBuilder.create()
 .setCorePoolSize(5)
 .setMaxPoolSize(10)
 .setWorkQueue(new LinkedBlockingQueue<>(100))
 .build();