Java Executor Framework

Java Executor Framework

Java provides its own multithreading framework called the Java Executor Framework which is introduced in JDK5 in java.util.concurrent package.

The Executor Framework in Java provides a high-level abstraction for managing concurrent tasks in a Java application. It simplifies multi-threading by handling tasks such as thread creation, management and task scheduling. One of its key features is the thread pool, which reuses existing threads instead of creating new ones, improving efficiency and resource management.?

Hierarchy of Executor :

The Key components of executor framework are :

  • Executor:- The Executor Interface is at the core of the framework and it provides the execute method(Runnable)? which takes tasks and then submits them to the thread pool for execution.

  1. execute(Runnable object):This function schedules the execution of a given command to occur sometime in the future. The command might run in a new thread, a pooled thread, or the calling thread, depending on how the executor is implemented.

executor.execute(threadObject);        

  1. submit(Callable object): Adds a task that returns a result to the list of executing tasks for execution. It returns a Future object which returns the result of the task after completion.

Future<String> result = executorService.submit(callableTask);        

  • ExecutorService : The ExecutorService interface is an extension of the Executor interface. It offers a more versatile method called submit, which is similar to execute. In addition to accepting Runnable objects, submit can also handle Callable objects, allowing tasks to return values. When you submit a task using this method, it returns a Future object. This Future object can be used to retrieve the return value from a Callable task and manage the status of both Callable and Runnable tasks.
  • ScheduledExecutorService: This extends the Executor framework to support scheduling tasks to run at specific times or with fixed time intervals. It's particularly useful for implementing tasks that need to be executed periodically, such as cleanup tasks or periodic data updates.
  • ThreadPoolExecutor:- This is one of the most commonly used implementations of the ExecutorService interface. It manages a pool of worker threads and provides fine-grained control over thread management, allowing you to specify parameters like the core pool size, maximum pool size, and various queueing strategies.

ThreadPoolExecutor executor = new ThreadPoolExecutor(int mainPoolSize, long keepAliveTime,int maximumPoolSize, TimeUnit unit,BlockingQueue<Runnable> workQueue);        

  • Executors Utility Class: Java provides the Executors utility class, which offers factory methods for creating instances of Executor and ScheduledExecutorService. It simplifies the process of creating thread pools with various configurations.

Types of Executor Framework:

1. SingleThreadExecutor:- It is designed to execute tasks sequentially, one at a time, on a single worker thread. This is useful in scenarios where you want to guarantee sequential execution of tasks, ensuring that they don't run concurrently. Single threaded pool is provided by the static newSingleThreadExecutor method of the Executors class.

  • Sequential Execution: It ensures that tasks are executed in tasks submitted order.
  • Worker Thread: It maintains a single worker thread to execute tasks. This thread is created and managed by the executor. Tasks are executed in a first-in, first-out (FIFO) order on this dedicated thread.

ExecutorService executor = Executors.newSingleThreadExecutor();

executor.execute(new Runnable() {

    public void run() {

        // Task logic here

    }

});

executor.shutdown();        

2. FixedThreadPool(n): It creates a fixed-size thread pool with a specified number of worker threads.Fixed thread pool is provided by the static newFixedThreadPool method of the Executors class.

  • Fixed Number of Threads: FixedThreadPool maintains a fixed and specified 'n' number of worker threads in the pool, when creating the executor. These threads are created at initialization and remain active throughout the lifetime of the executor.
  • Thread Reuse:The threads in a FixedThreadPool are reused to execute tasks. When a task is submitted, it is assigned to one of the available threads for execution. If all threads are busy, additional tasks are queued until a thread becomes available.
  • Blocking Queue:Tasks that are submitted to a FixedThreadPool and can't be immediately executed due to all threads being busy are placed in a blocking queue. They are executed as soon as a thread becomes available.
  • Optimal for Controlled Concurrency:This type of executor is ideal when you need to control the level of concurrency in your application. You can precisely specify how many threads are available for executing tasks, which can help to manage resource usage and prevent resource contention.

ExecutorService executor = Executors.newFixedThreadPool(5);

// Submit tasks for execution

for (int i = 0; i < 10; i++) {

    executor.execute(new Runnable() {

        public void run() {

            // Task logic here

        }

    });

}        

3. CachedThreadPool: It creates a thread pool that can dynamically adjust the number of worker threads based on the workload. It uses a SynchronousQueue queue. Some key points mentioned in below:?

  • Dynamic Thread pool: This pool doesn’t have a fixed thread pool size like fixedThreadPool. It manages the number of threads in the pool on the basis of no of tasks and workload.

  • Thread Reuse: In CachedThreadPool, threads are utilized repeatedly to execute tasks. When a task is submitted, it's assigned to an available thread for execution. If there are no available threads, a new one is created dynamically. Threads that remain idle for a set period are eventually terminated and removed from the pool to conserve resources. This approach optimizes resource utilization by reusing threads and dynamically adjusting the pool size based on workload.

  • Suitable for unpredictable Workloads: This type of executor is well-suited for scenarios with fluctuated workloads unpredictably or when the number of tasks varies widely. It can efficiently allocate threads as needed and shrink the thread pool during periods of low activity.This adaptive behavior optimizes performance and resource utilization, making it well-suited for dynamic and unpredictable environments.

ExecutorService executor = Executors.newCachedThreadPool();

// Submit tasks for execution

for (int i = 0; i < 10; i++) {

    executor.execute(new Runnable() {

        public void run() {

            // Task logic here

        }

    });

}        

4.ScheduledExecutor: Scheduled executors are based on the interface ScheduledExecutorService which extends the ExecutorService interface.It is specifically designed for scheduling tasks to run at specified times or with fixed time intervals.Some important key points explained in below:

  • Task Scheduling: The primary purpose of ScheduledExecutor is to schedule tasks to run at specific times in the future or at regular intervals. This is particularly useful for automating periodic tasks, such as data updates, backups, or sending out notifications.
  • Multiple Implementations: Java provides several implementations of ScheduledExecutor, most common one ScheduledThreadPoolExecutor. This allows you to choose the level of concurrency and scheduling flexibility that suits your application.
  • Delayed Execution: Schedule tasks to run after a certain delay from the current time or at an absolute time in the future. This flexibility enables precise control when tasks should be executed.
  • Recurring Tasks: ScheduledExecutor can also be used to schedule recurring tasks that run at fixed time intervals. For example, you can schedule a task to run every hour or every day.

Methods:?

  • schedule ?- schedules a task to run after a specified delay.

schedule(Runnable ob, long delay, TimeUnit unit)

schedule(Callable<V> callable, long delay, TimeUnit unit)        

  • scheduleAtFixedRate : This method executes the task with a fixed interval when the previous task ends.

scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit);        

  • scheduleWithFixedDelay : This method starts the delay count after the current task completes.

scheduledExecService.scheduleWithFixedDelay(Runnable command, long initialDelay, long period, TimeUnit unit) ;        
ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);

// Schedule a task to run after a delay of 5 seconds

executor.schedule(new Runnable() {

    public void run() {

        // Task logic here

    }

}, 5, TimeUnit.SECONDS);        

Future Object: The result of the task submitted for execution to an executor can be accessed using the java.util.concurrent.The future object returned by the executor. Future can be thought of as a promise made to the caller by the executor. The future interface is mainly used to get the results of Callable results. whenever the task execution is completed, it is set in this Future object by the executor.

Future<String> result = executorService.submit(callableTask);        

要查看或添加评论,请登录

社区洞察

其他会员也浏览了