Java Executor and ExecutorService examples
When you need more then one Thread
to process multiple tasks in Java, you typically create multiple
Threads
and start them using new Thread(r).start()
. But this way you need to manage
Thread
life cycle and you can't tune number of threads you actually need to perform the tasks.
This is where java.util.Executor
comes in very useful. You can use your choice of implementation
of Executor
interface and thus it lets you decouple the submission of task to execution of task.
1) Examples of Executor interface implementation
Executor that executes task asynchronously
In below example we implement Executor
which starts a new thread for each submitted task.
A task is submitted by calling Executor execute(Runnable r)
which accepts a Runnable
type argument.
import java.util.concurrent.Executor; public class TaskExecutor implements Executor { public void execute(Runnable r) { new Thread(r).start(); } public static void main(String[] args) { TaskExecutor taskExecutor = new TaskExecutor(); Runnable runnable = () -> {System.out.println("Thread implementing Runnable started");}; taskExecutor.execute(runnable); } }
Output :
Thread implementing Runnable started
Executor that executes task synchronously
Its not necessary that each submitted task would be run asynchronously. You can call Runnable run()
inside the execute
method to make the task run synchronously.
import java.util.concurrent.Executor; public class TaskExecutor implements Executor { public void execute(Runnable r) { r.run(); } public static void main(String[] args) { TaskExecutor taskExecutor = new TaskExecutor(); Runnable runnable = () -> {System.out.println("Thread implementing Runnable started");}; taskExecutor.execute(runnable); } }
Output :
Thread implementing Runnable started
2) ExecutorService and Executors examples
There are various useful Executor
implementations provide by Executors
class is a factory of Executor
which returns ExecutorService
type that extends Executor
.
Below are some of the important Executor
implementations:
newSingleThreadExecutor()
returns anExecutor
with single thread. If there are more than one tasks submitted, only one task will be active and others will be put in a queue.newFixedThreadPool()
returns anExecutor
with fixed number of threads. If there are more tasks submitted than the thread pool size, then rest of the tasks will be put in a queue.newCachedThreadPool()
returns anExecutor
which creates new Thread as needed and put into a pool. Threads that are not used for sixty seconds are terminated and removed from the cache.newSingleThreadScheduledExecutor()
returns anExecutor
which will schedule the task to run after a certain interval.
Executor
will accept a Runnable
in submit(Runnable r)
method which can be created as below using Lambda expression
() -> System.out.println("Thread started")
public class MyClass implements Runnable { public void run() { System.out.println("Thread started"); } }
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; public class ExecutorServiceExample { public static void main(String[] args) { // fixed thread pool with four threads ExecutorService service = Executors.newFixedThreadPool(4); service.submit(() -> System.out.println("Thread started")); // cached thread pool service = Executors.newCachedThreadPool(); service.submit(() -> System.out.println("Thread started")); // single thread pool service = Executors.newSingleThreadExecutor(); service.submit(() -> System.out.println("Thread started")); service.shutdown(); ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(); scheduledExecutorService.schedule(() -> System.out.println("Thread scheduled started"), 2000, TimeUnit.MILLISECONDS); scheduledExecutorService.scheduleAtFixedRate(() -> System.out.println("Thread scheduleAtFixedRate started"), 1000, 2000, TimeUnit.MILLISECONDS); } }
Output :
Thread started Thread started Thread started Thread scheduleAtFixedRate started Thread scheduled started Thread scheduleAtFixedRate started Thread scheduleAtFixedRate started
ExecutorService invokeAll() and invokeAny() example
invokeAll()
will take multiple Callable
instances and start running all the tasks while
invokeAny()
will take multiple Callable
instances and returns the result of the task which is completed successfully.
import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ExecutorServiceExample { public static void main(String[] args) { ExecutorService service = Executors.newFixedThreadPool(2); List<Callable<String>> tasks = new ArrayList<>(); tasks.add(() -> "task1"); tasks.add(() -> "task2"); service = Executors.newFixedThreadPool(2); try { service.invokeAll(tasks); } catch (InterruptedException e) { e.printStackTrace(); } tasks.forEach(task -> { try { System.out.println(task.call()); } catch (Exception e) { e.printStackTrace(); } }); service.shutdown(); service = Executors.newFixedThreadPool(2); try { System.out.println(service.invokeAny(tasks)); } catch (InterruptedException | ExecutionException e1) { e1.printStackTrace(); } service.shutdown(); } }
Output :
task1 task2
3) Shutting down ExecutorService
ExecutorService shutdown() example
shutdown()
will stop all the threads which are executed successfully and will not accept new tasks
import java.util.concurrent.Executors; import java.util.concurrent.ExecutorService; public class MyThread implements Runnable { public void run() { System.out.println(Thread.currentThread().getName() + " started"); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " complete"); } public static void main(String[] args) { MyThread myThread = new MyThread(); // single thread pool ExecutorService service = Executors.newSingleThreadExecutor(); service.submit(myThread); service.shutdown(); service.submit(myThread); } }
Output :
pool-1-thread-1 started Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@10dea4e rejected from java.util.concurrent.ThreadPoolExecutor@647e05 [Shutting down, pool size = 1, active threads = 1, queued tasks = 0, completed tasks = 0] at java.util.concurrent.ThreadPoolExecutor$AbortPolicy .rejectedExecution(Unknown Source) at java.util.concurrent.ThreadPoolExecutor .reject(Unknown Source) at java.util.concurrent.ThreadPoolExecutor .execute(Unknown Source) at java.util.concurrent.AbstractExecutorService .submit(Unknown Source) at java.util.concurrent. Executors$DelegatedExecutorService.submit(Unknown Source) at MyThread.main(MyThread.java:24) pool-1-thread-1 complete
ExecutorService shutdownNow() example
shutdownNow()
will stop all the running threads and will return list of the tasks that were awaiting execution
In below example observe that first thread sleeps and is immediately shutdown and is not allowed to complete the task.
import java.util.concurrent.Executors; import java.util.concurrent.ExecutorService; public class MyThread implements Runnable { public void run() { System.out.println(Thread.currentThread().getName() + " started"); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " complete"); } public static void main(String[] args) { MyThread myThread = new MyThread(); // single thread pool ExecutorService service = Executors.newSingleThreadExecutor(); service.submit(myThread); service.shutdownNow(); } }
Output :
java.lang.InterruptedException: sleep interrupted at java.lang.Thread.sleep(Native Method) at MyThread.run(MyThread.java:8) at java.util.concurrent.Executors$RunnableAdapter.call (Unknown Source) at java.util.concurrent.FutureTask.run(Unknown Source) at java.util.concurrent.ThreadPoolExecutor .runWorker(Unknown Source) at java.util.concurrent.ThreadPoolExecutor$Worker .run(Unknown Source) at java.lang.Thread.run(Unknown Source) pool-1-thread-1 started pool-1-thread-1 complete
References :