A Guide To The Java Executor Service Baeldung
User Manual: Pdf
Open the PDF directly: View PDF .
Page Count: 7
3/30/2018 A Guide to the Java ExecutorService | Baeldung
http://www.baeldung.com/java-executor-service-tutorial 1/11
A Guide to the Java
ExecutorService
Last modied: January 26, 2018
by baeldung (http://www.baeldung.com/author/baeldung/)
Java (http://www.baeldung.com/category/java/)
I just announced the new
Spring 5
modules in REST With Spring:
>> CHECK OUT THE COURSE (/rest-with-spring-course#new-modules)
1. Overview
ExecutorService
(https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html)
is a
framework provided by the JDK which simplies the execution of tasks in asynchronous mode.
Generally speaking,
ExecutorService
automatically provides a pool of threads and APIfor
assigning tasks to it.
Further reading:
Guide to the Overview of the Guide to
+
(http://baeldung.com)
3/30/2018 A Guide to the Java ExecutorService | Baeldung
http://www.baeldung.com/java-executor-service-tutorial 2/11
Fork/Join Framework
in Java
(http://www.baeldung.com/java-
fork-join)
An intro to the fork/join
framework presented in Java 7
and the tools to help speed up
parallel processing by
attempting to use all available
processor cores.
Read more
(http://www.baeldung.com/java-
fork-join)
java.util.concurrent
(http://www.baeldung.com/java-
util-concurrent)
Discover the content of the
java.util.concurrent package.
Read more
(http://www.baeldung.com/java-
util-concurrent)
java.util.concurrent.Locks
(http://www.baeldung.com/
concurrent-locks)
In this article, we explore
various implementations of
the Lock interface and the
newly introduced in Java 9
StampedLock class.
Read more
(http://www.baeldung.com/java-
concurrent-locks)
2. Instantiating
ExecutorService
2.1. Factory Methods of the
Executors
Class
The easiest way to create
ExecutorService
is touse one of the factory methods of the
Executors
class.
For example, the following line of code will create a thread-pool with 10 threads:
The are several otherfactorymethods to create predened
ExecutorService
that meet specic
use cases. To nd the best method for your needs, consult Oracle’s ocial documentation
(https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Executors.html).
2.2. Directly Create an
ExecutorService
Because
ExecutorService
is an interface, an instance of any its implementations canbe used.
There are severalimplementations to choose fromin the
java.util.concurrent
(https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executors.html)
package or
you can create your own.
For example, the
ThreadPoolExecutor
class has a few constructors which can be used
tocongure an executor service and its internal pool.
1 ExecutorService executor = Executors.newFixedThreadPool(10);
3/30/2018 A Guide to the Java ExecutorService | Baeldung
http://www.baeldung.com/java-executor-service-tutorial 3/11
You may notice that the code above is very similarto thesource code
(http://grepcode.com/le/repository.grepcode.com/java/root/jdk/openjdk/6-
b14/java/util/concurrent/Executors.java#Executors.newSingleThreadExecutor%28%29) of the
factory method
newSingleThreadExecutor().
For most
cases, a detailed manual conguration isn’t
necessary.
3. Assigning Tasks to the
ExecutorService
ExecutorService
can execute
Runnable
and
Callable
tasks. To keep things simple in this
article,two primitive tasks will be used. Notice that lambda expressions are used here instead of
anonymous inner classes:
Tasks can be assigned to the
ExecutorService
using several methods, including
execute()
, which
is inherited from the
Executor
interface,and also
submit()
,
invokeAny(), invokeAll().
The
execute()
method is
void,
and it doesn’t give any possibility to get the result of task’s
execution or to check the task’s status (is it running or executed).
submit()
submits a
Callable
or a
Runnable
task to an
ExecutorService
andreturns a result of
type
Future
.
1
2
3
ExecutorService executorService =
new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Runnable runnableTask = () -> {
try {
TimeUnit.MILLISECONDS.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
};
Callable<String> callableTask = () -> {
TimeUnit.MILLISECONDS.sleep(300);
return "Task's execution";
};
List<Callable<String>> callableTasks = new ArrayList<>();
callableTasks.add(callableTask);
callableTasks.add(callableTask);
callableTasks.add(callableTask);
1 executorService.execute(runnableTask);
1
2
Future<String> future =
executorService.submit(callableTask);
3/30/2018 A Guide to the Java ExecutorService | Baeldung
http://www.baeldung.com/java-executor-service-tutorial 4/11
invokeAny()
assigns a collection of tasks to an
ExecutorService,
causing each to be executed, and
returns the result of a successful execution of one task (if there was a successful execution)
.
invokeAll()
assigns a collection of tasks to an
ExecutorService,
causing each to be executed, and
returns the result of all taskexecutions in the form of a list of objects of type
Future.
Now, before going any further, two more things must be discussed: shutting down
an
ExecutorService
and dealing with
Future
return types.
4. Shutting Down an
ExecutorService
In general, the
ExecutorService
will not be automatically destroyed when there is not task to
process. It will stay alive and wait for new work to do.
In some cases thisis very helpful; for example, if anapp needs to process tasks which appear on
an irregular basis or the quantity of these tasks is not knownat compiletime.
On the other hand, an app could reach its end, but it will not be stopped because a waiting
ExecutorService
will cause theJVM to keep running.
To properly shut down an
ExecutorService
, we have the
shutdown()
and
shutdownNow()
APIs.
The
shutdown()
method doesn’t cause an immediate destruction of the
ExecutorService.
It will
make the
ExecutorService
stop accepting new tasks and shut down after all running threads
nish their current work.
The
shutdownNow()
method tries to destroythe
ExecutorService
immediately, but it doesn’t
guarantee that all the running threads will be stopped at the same time. This method returns a list
of tasks which are waiting to be processed. It is up to thedeveloper to decide what to do with
thesetasks.
One good wayto shut down the
ExecutorService
(which is also recommended by Oracle
(https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ExecutorService.html))is to
use both of these methods combined with the
awaitTermination()
method. With this approach,
the
ExecutorService
will rst stop taking new tasks, the wait up to a specied period of time for all
tasks to be completed. If that time expires,theexecution is stopped immediately:
1 String result = executorService.invokeAny(callableTasks);
1 List<Future<String>> futures = executorService.invokeAll(callableTasks);
1 executorService.shutdown();
1 List<Runnable> notExecutedTasks = executorService.shutDownNow();
3/30/2018 A Guide to the Java ExecutorService | Baeldung
http://www.baeldung.com/java-executor-service-tutorial 5/11
5. The
Future
Interface
The
submit()
and
invokeAll()
methods return an object or a collection of objects of
type
Future
,whichallows us to get the result of a task’s execution or to check the task’s status (is
it running or executed).
The
Future
interface provides a special blocking method
get()
which returns an actual result of
the
Callable
task’s execution or
null
in the case of
Runnable
task. Calling the
get()
method while
the task is still running will cause execution to block until the task is properly executed and the
result is available.
With very long blocking caused by the
get()
method, an application’s performancecandegrade. If
the resultingdata is not crucial, it is possible to avoid such a problemby usingtimeouts:
If the execution period is longer than specied (in this case 200 milliseconds), a
TimeoutException
will be thrown.
The
isDone()
method can be used to checkif the assigned task is already processed or not.
The
Future
interface also provides forthe cancellation of task execution with the
cancel()
method,
and to check the cancellation with
isCancelled()
method:
6. The
ScheduledExecutorService
Interface
1
2
3
4
5
6
7
8
executorService.shutdown();
try {
if (!executorService.awaitTermination(800, TimeUnit.MILLISECONDS)) {
executorService.shutdownNow();
}
} catch (InterruptedException e) {
executorService.shutdownNow();
}
1
2
3
4
5
6
7
Future<String> future = executorService.submit(callableTask);
String result = null;
try {
result = future.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
1 String result = future.get(200, TimeUnit.MILLISECONDS);
1
2
boolean canceled = future.cancel(true);
boolean isCancelled = future.isCancelled();
3/30/2018 A Guide to the Java ExecutorService | Baeldung
http://www.baeldung.com/java-executor-service-tutorial 6/11
The
ScheduledExecutorService
runs tasksafter some predened delay and/or periodically. Once
again, the bestway to instantiate a
ScheduledExecutorService
is to use the factory methods of
the
Executors
class.
For this section, a
ScheduledExecutorService
with one thread will be used:
To schedule a single task’s execution after a xed delay, us the
scheduled()
method of the
ScheduledExecutorService
. There are two
scheduled()
methods that allow you to
execute
Runnable
or
Callable
tasks:
The
scheduleAtFixedRate()
method lets execute a task periodically after a xed delay. The code
above delays for one second before executing
callableTask
.
Thefollowing block of code will execute a task after an initial delay of 100 milliseconds, and after
that, it will execute the same task every 450 milliseconds. If the processorneeds more time to
execute an assigned task than the
period
parameter of the
scheduleAtFixedRate()
method,
the
ScheduledExecutorService
will wait until the current task is completed before starting the
next:
If it is necessary to have a xed length delay between iterations of the task,
scheduleWithFixedDelay()
should be used. For example, the following code will guarantee a 150-
millisecond pause between the end of the current execution and the start of another one.
According to the
scheduleAtFixedRate()
and
scheduleWithFixedDelay()
method contracts, period
execution of the task will end at thetermination of the
ExecutorService
or if an exception is
thrownduring task execution
.
7.
ExecutorService
vs. Fork/Join
After the release ofJava 7, many developers decided that the
ExecutorService
framework should
be replacedby the fork/join framework. This isnot always the right decision, however.Despite
the simplicity of usage and the frequent performance gains associated with fork/join, there is also
a reduction in the amount of developer control over concurrent execution.
1
2
ScheduledExecutorService executorService = Executors
.newSingleThreadScheduledExecutor();
1
2
Future<String> resultFuture =
executorService.schedule(callableTask, 1, TimeUnit.SECONDS);
1
2
Future<String> resultFuture = service
.scheduleAtFixedRate(runnableTask, 100, 450, TimeUnit.MILLISECONDS);
1 service.scheduleWithFixedDelay(task, 100, 150, TimeUnit.MILLISECONDS);
Download
The E-book
Buildinga REST API with Spring
3/30/2018 A Guide to the Java ExecutorService | Baeldung
http://www.baeldung.com/java-executor-service-tutorial 7/11
ExecutorService
gives the developer theability to control the numberof generated threads and
the granularity of tasks which should be executed by separate threads. The best use case for
ExecutorService
is the processing of independent tasks, such astransactions or requests
according to the scheme “one thread for one task.”
In contrast, according to Oracle’s documentation
(https://docs.oracle.com/javase/tutorial/essential/concurrency/forkjoin.html), fork/join was
designed to speed up workwhich can be broken into smaller pieces recursively.
8. Conclusion
Even despite the relative simplicity of
ExecutorService
, there are a few common pitfalls. Let’s
summarize them:
Keeping an unused
ExecutorService
alive:There is a detailed explanation in section 4 of this
article about how to shut down an
ExecutorService
;
Wrong thread-pool capacity while using xed length thread-pool:It is very important to
determinehow many threads the application will need to execute tasks eciently. Athread-pool
that is too large will cause unnecessary overheadjust to create threadswhich mostlywill be in
thewaiting mode. Too fewcan make an application seemunresponsive because of long waiting
periods for tasks in the queue;
Calling a
Future
‘s
get()
method after task cancellation:Anattempt to get the result of an
already canceled task will trigger a
CancellationException.
Unexpectedly-long blocking with
Future
‘s
get()
method:Timeouts should be used to avoid
unexpected waits.
The code for this article is available in a GitHub repository
(https://github.com/eugenp/tutorials/tree/master/core-java-concurrency).
I just announced the new Spring 5 modules in REST With Spring:
>> CHECK OUT THE LESSONS (/rest-with-spring-course#new-modules)
g p g
4?
Email Address
Download