Full Stack Web Development Internship Program
- 5k Enrolled Learners
- Weekend/Weekday
- Live Class
Java programming language works very efficiently with multithreaded applications which require the tasks to be executed concurrently in a thread. It becomes difficult for any application to execute a large number of threads simultaneously. So to overcome this problem, Java comes with ExecutorService which is a sub-interface of the Executors framework. In this article, we will discuss the functionality of ExecutorService in Java. Following are the topics covered in this blog:
It is fairly easier to make and execute one or two threads simultaneously. But it becomes difficult when the number of threads increases to a significant number. Large multi-threaded applications will have hundreds of threads running simultaneously. Therefore it makes complete sense to separate the thread creation from thread management in an application.
The executor is a framework helps you in creating and managing threads in an application. The executor framework helps you in the following tasks.
Thread Creation: It provides a variety of methods for the creation of threads that helps in running your applications concurrently.
Thread Management: It also manages the thread life cycle. You need not worry if the thread is active, busy or dead before submitting the task for execution.
Task Submission And Execution: Executor framework provides methods for task submission in the thread pool, It also gives the power to decide if the thread will be executed or not.
It is a sub-interface of the executor framework that adds certain functionalities to manage the thread life cycle of an application. It also provides a submit() method which can accept both runnable and callable objects.
In the following example, we will create an ExecutorService with a single thread and then submit the task to be executed inside the thread.
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Example { public static void main(String[] args) { System.out.println(" Inside : " + Thread.currentThread().getName()); System.out.println("creating ExecutorService"); ExecutorService executorservice = Executors.newSingleThreadExecutor(); System.out.println("creating a runnable"); Runnable runnable = () -> { System.out.println("inside: "+ Thread.currentThread().getName()); }; System.out.println("submit the task specified by the runnable to the executorservice"); executorservice.submit(runnable); } }
Output: Inside: main creating ExecutorService creating a runnable submit the task specified by the runnable to the executorservice inside: pool-1-thread-1
The above program shows how we can create an ExecutorService and execute a task inside the executor. If a task is submitted for execution and thread is currently busy executing another task, then the task will wait in a queue until the thread is free to execute it.
When you run the above program, the program will never exit. You will need to shut it down explicitly since the executor service keeps listening for new tasks.
ExecutorService is very much similar to a thread pool. In fact, the implementation of the ExecutorService in the java.util.concurrent package is a threadpool implementation. The ExecutorService has the following implementations in the java.util.concurrent package:
The ThreadPoolExecutor executes the given tasks using one of its internally pooled threads.
Creating a threadPoolExecutor
int corePoolSize = 5; int maxPoolSize = 10; long keepAliveTime = 5000; ExecutorService threadPoolExecutor = new threadPoolExecutor( corePoolSize, maxPoolSize, keepAliveTime, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
The java.util.concurrent.ScheduledThreadPoolExecutor is an ExecutorService that can schedule tasks to run after a delay or to execute repeatedly with a fixed interval of time in between each execution.
Example
ScheduledExecutorService scheduledexecutorservice = Executors.newScheduledThreadPool (5); ScheduledFuture scheduledfuture = scheduledExecutorService.schedule(new Callable(){ public Object call() throws Exception{ System.out.println("executed"); return "called"; } }, 5, TimeUnit.SECONDS);
There are a few different ways to delegate tasks to an ExecutorService.
execute(Runnable)
submit(Runnable)
invokeAny()
invokeAll()
Java ExecutorService execute(Runnable) takes a java.lang.Runnable object and executes it asynchronously.
ExecutorService executorService = Executors.newSingleThreadExecutor(); executorService.execute(new Runnable(){ public void run(){ System.out.println("asynchronous task"); } }); executorService.shutdown();
There is no way to get the result of the execute Runnable, for that you have to use the Callable.
Java ExecutorService submit(Runnable) method takes a Runnable implementation and returns a future object. The future object can be used to check if the Runnable has finished executing.
Future future = executorService.submit(new Runnable(){ public void run(){ System.out.println(:asynchronous task"); } }); future.get(); //returns null if the task is finished correctly.
The Java ExecutorService submit(Callable) method is similar to submit(Runnable) but it takes Java Callable instead of Runnable.
Future future = executorService.submit(new Callable(){ public Object call() throws Exception{ System.out.println("Asynchronous callable"); return "Callable Result"; } }); System.out.println("future.get() = " future.get());
Output: Asynchroous callable future.get = Callable Result
The invokeAny() method takes a collection of Callable objects. Invoking this method does not return any future, but returns the result of one of the Callable objects.
ExecutorService executorService = Executors.newSingleThreadExecutor(); Set<Callable<String>> callables = new HashSet<Callable<String>>(); callables.add(new Callable<String>(){ public String call() throws Exception{ return"task A"; } }); callables.add(new Callable<String>(){ public String call() throws Exception{ return"task B"; } }); callables.add(new Callable<String>(){ public String call() throws Exception{ return"task C"; } }); String result = executorService.invokeAny(callables); System.out.println("result = " + result); executorService.shutdown();
When you run the above code, the result changes. It might be Task A, Task B and so on.
The invokeAll() method invokes all Callable objects passed as parameters. It returns the future objects which can be used to get the results of the execution of each Callable.
ExecutorService executorService = Executors.newSingleThreadExecutor(); Set<Callable<String>> callables = new HashSet<Callable<String>>(); callables.add(new Callable<String>(){ public String call() throws Exception{ return "Task A"; } }); callables.add(new Callable<String>(){ public String call() throws Exception{ return "Task B"; } }); callables.add(new Callable<String>(){ public String call() throws Exception{ return "Task C"; } }); List<Future<String>> futures = executorService.invokeAll(callables); for(Future<String> future: futures){ System.out.println(" future.get = " + future.get()); } executorService.shutdown();
The runnable and callable interfaces are very similar to each other. The difference is visible in the declaration of the interfaces. Both the interfaces represent a task that can be executed concurrently by a thread or ExecutorService.
Callable Declaration:
public interface Callable{ public object call() throws Exception; }
Runnable Declaration:
public interface Runnable{ public void run(); }
The main difference between the two is that the call() method can return an object from the method call. And call() method can throw an exception while run() method cannot.
cancel task
You can cancel the task submitted to ExecutorService by simply calling the cancel method on the future submitted when the task is submitted.
future.cancel();
In order to keep the threads from running even after the execution is complete, you should shut down the ExecutorService.
shutdown()
To terminate the threads inside an ExecutorService you can call the shutdown() method.
executorService.shutdown();
This brings us to the end of this article where we have learned how we can use ExecutorService to execute tasks in a thread. I hope you are clear with all that has been shared with you in this tutorial.
If you found this article on “ExecutorService in Java” relevant, check out the Edureka Java Course, a trusted online learning company with a network of more than 250,000 satisfied learners spread across the globe.
We are here to help you with every step on your journey and come up with a curriculum that is designed for students and professionals who want to be a Java Developer. The course is designed to give you a head start into Java programming and train you for both core and advanced Java concepts along with various Java frameworks like Hibernate & Spring.
If you come across any questions, feel free to ask all your questions in the comments section of “ExecutorService in Java” and our team will be glad to answer.
Course Name | Date | |
---|---|---|
Java Certification Training Course | Class Starts on 28th January,2023 28th January SAT&SUN (Weekend Batch) | View Details |
Java Certification Training Course | Class Starts on 25th February,2023 25th February SAT&SUN (Weekend Batch) | View Details |
edureka.co