The executor framework is Java enables you to separate thread creation and management for the implementation of concurrent tasks. With executor framework, you don’t have to worry about creation and management of threads, only create tasks and submit to the executor.
Let us see important classes and interfaces of executor framework.
1. Executor
This is an interface in java.util.concurrent
package. An executor executes submitted Runnable
tasks. This is the main interface in executor framework. This interface provides a way to separate task submission from the thread management. The separation of creation and management of tasks is done by submitting tasks to the executor rather that manually starting the thread by calling start()
, like:
executor.execute(runnableTask1); executor.execute(runnableTask2);
Here, executor is an instance of Executor
interface. We’ll see later in this tutorial ways to create an Executor
.
This interface has one method submit with following signature:
void execute(Runnable task)
This method is used to execute the submitted tasks. Since this method has no return type, this method can not be used to track progress of the submitted task. Following are sub-interfaces of Executor
:
ExecutorService
ScheduledExecutorService
2. ExecutorService
This interface is a sub-interface of Executor
and is present in java.util.concurrent
package. This interface has few methods which return a Future
object, which is used for tracking progress of submitted tasks.
Following are its implementing classes:
AbstractExecutorService
ForkJoinPool
ScheduledThreadPoolExecutor
ThreadPoolExecutor
This interface has an overloaded method submit()
which is used to submit the tasks to executor for execution. Unlike the execute()
method in Executor
interface, this method returns a Future
object that can be used to cancel execution and/or wait for completion. Following are overloaded versions of submit()
:
<T>Future<T> submit(Callable<T> task)
Future<?> submit(Runnable task)
<T>Future<T> submit(Runnable task, T result)
3. Executors
This is a class present in java.util.concurrent
package. This class provides factory and utility methods for Executor
, ExecutorService
, ScheduledExecutorService
, ThreadFactory
, and Callable
. Few important methods provided in this class are:
- st
atic Callable<Object> callable(Runnable task)
static ExecutorService newFixedThreadPool(int nThreads)
static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory)
static ExecutorService newSingleThreadExecutor()
static ThreadFactory privilegedThreadFactory()
4. Callable
This is an interface present in java.util.concurrent
package. Callable
represents a task that returns a result and may throw an exception. This interface has single method call()
:
V call()
5. Future
A Future
represents the result of an asynchronous task. Methods of Future
allows you to check the progress of the task. With Future
object you can check whether the task is complete or not and can get the result of task. Future
provides methods to cancel the task or check if the task is cancelled or not, wait for the completion of the task and get the result and check if the task is done. Following are the methods provided by the Future
interface:
boolean cancel(boolean mayInterruptIfRunning)
V get()
V get(long timeout, TimeUnit unit)
boolean isCancelled()
boolean isDone()
6. Example
Let us see usage of executor framework with an example. In this example, we’ll create ten Runnable
tasks and submit the tasks to a fixed thread pool of size 2. We’ll verify that at only two threads are running at a time.
We suggest you to run this program and observe the output in console. You’ll observe that at a given point of time only 2 tasks are running. However, we have submitted 10 tasks to the executor.
package com.learnitweb; import java.util.concurrent.Executors; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; class Task implements Runnable { private String name; public Task(String name) { this.name = name; } public String getName() { return name; } public void run() { try { Long duration = (long) (Math.random() * 10); System.out.println("Executing: " + name); TimeUnit.SECONDS.sleep(2); } catch (Exception e) { e.printStackTrace(); } } } public class ExecutorExample { public static void main(String args[]) { ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(2); for (int i = 1; i <= 10; i++) { Task task = new Task("Task " + i); System.out.println("Submitting: " + task.getName()); executor.execute(task); } executor.shutdown(); } }
Output
Submitting: Task 1 Submitting: Task 2 Submitting: Task 3 Submitting: Task 4 Submitting: Task 5 Submitting: Task 6 Submitting: Task 7 Submitting: Task 8 Submitting: Task 9 Submitting: Task 10 Executing: Task 1 Executing: Task 2 Executing: Task 3 Executing: Task 4 Executing: Task 5 Executing: Task 6 Executing: Task 7 Executing: Task 8 Executing: Task 9 Executing: Task 10