Java Executor Framework
Java Executor Framework
- Thread synchronization
- Thread waiting
- Thread joining
- Thread locking
- Thread notification
- Handling dead lock
And many more concurrent execution issues that arises out of the application requirement. In real project implementation some time
it is very difficult to control multithreading applications. The behaviors of the threads are also dependent on the environment where
the application is deployed and running. So the same application might behave in a different way on different deployment
environment. For example, the processor speed, the RAM size, the band width all has a direct impact on the multithreading
application. So you have to keep all these factors in mind before creating architecture for multithreading applications.
Executors framework (java.util.concurrent.Executor), released with the JDK 5 in package java.util.concurrent is used to run the
Runnable objects without creating new threads every time and mostly re-using the already created threads.
The Executor framework is an abstraction layer over the actual implementation of java multithreading. It is the first concurrent
utility framework in java and used for standardizing invocation, scheduling, execution and control of asynchronous tasks in parallel
threads. The execution rules are defined during the creation of the constructor. And then the executor runs the concurrent threads
following the rules set earlier.
Executor implementation in java uses thread pools which consists of worker threads. The entire management of worker threads is
handled by the framework. So the overhead in memory management is much reduced compared to earlier multithreading
approaches.
The Java Executor framework provides multi-threading applications an easy abstraction layer. The executor abstraction layer
hides the critical parts of concurrent execution and the programmer only concentrates on the business logic implementation. In java
executor framework all parallel works are considered as tasks instead of simple threads. So the application now deals simply with
Output as PDF file has been powered by [ Universal Post Manager ] plugin from www.ProfProjects.com | Page 1/17 |
This page was exported from - TechnicalStack
Export date: Sun Mar 1 15:02:29 2020 / +0000 GMT
instances of Runnable (which is basically collections of tasks or parallel works) and then it is passed to an Executor to process. The
ExecutorServiceinterface extends the simplistic Executor interface. The Java Executor framework has life cycle methods to
manage the entire concurrent execution flow.
The Java Executor framework creates tasks by using instances of Runnable or Callable. In case of Runnable, the run () method
does not return a value or throw any checked exception. But Callable is a more functional version in that area. It defines a call ()
method that allows the return of some computed value which can be used in future processing and it also throws an exception if
necessary.
The FutureTask class is another important component which is used to get future information about the processing. An instance of
this class can wrap either a Callable or a Runnable. You can get an instance of this as the return value of submit () method of an
ExecutorService. You can also manually wrap your task in a FutureTask before calling execute () method.
Creating an executor
First you need to create an instance of an Executor or ExecutorService. The Executor class has a number of static factory methods
to create an ExecutorService depending upon the requirement of the application. Following are two main methods to create executor
service.
The newFixedThreadPool () returns a ThreadPoolExecutor instance with an initialized and unbounded queue and a fixed number
of threads.
The newCachedThreadPool () returns a ThreadPoolExecutor instance initialized with an unbounded queue and unbounded
number of threads.
Output as PDF file has been powered by [ Universal Post Manager ] plugin from www.ProfProjects.com | Page 2/17 |
This page was exported from - TechnicalStack
Export date: Sun Mar 1 15:02:36 2020 / +0000 GMT
available. These pools will typically improve the performance of programs that execute many short-lived asynchronous tasks. If no
existing thread is available, a new thread will be created and added to the pool. Threads that have not been used for 60 seconds are
terminated and removed from the cache.
ExecutorService execService = Executors.newFixedThreadPool(10);
This approach creates a thread pool that reuses a fixed number of threads. Created nThreads will be active at the runtime. If
additional tasks are submitted when all threads are active, they will wait in the queue until a thread is available.
ExecutorService execService = Executors.newSingleThreadExecutor();
This approach creates an Executor that uses a single worker thread operating off an unbounded queue. Tasks are guaranteed to
execute sequentially, and no more than one task will be active at any given time.
Example :
The following class implements Runnable and its instances will be used as a task in the next section of code.
SimpleTask.java
package com.technicalstack.core.executorframwork;
@Override
public void run() {
System.out.println("SimpleTask uing Runnable: Executing Logic...!");
RunnableClient
package com.technicalstack.core.executorframwork;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
executorService.submit(runnable);
executorService.shutdown();
Output:
SimpleTask uing Runnable: Executing Logic...!
-------------------------------------------------------------------------------------
Callable Example:
Output as PDF file has been powered by [ Universal Post Manager ] plugin from www.ProfProjects.com | Page 3/17 |
This page was exported from - TechnicalStack
Export date: Sun Mar 1 15:02:36 2020 / +0000 GMT
CallableTask.java
package com.technicalstack.core.executorframework;
import java.util.concurrent.Callable;
@Override
public Object call() throws Exception {
String s="Callable Task Run at "+System.currentTimeMillis();
return s;
}
CallableClient.java
package com.technicalstack.core.executorframework;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
while (listen) {
if (future.isDone()) {
String result;
try {
result = future.get();
listen = false;
System.out.println(result);
} catch (InterruptedException | ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
Output as PDF file has been powered by [ Universal Post Manager ] plugin from www.ProfProjects.com | Page 4/17 |
This page was exported from - TechnicalStack
Export date: Sun Mar 1 15:02:36 2020 / +0000 GMT
Java Concurrency interview question- In year 2004 when technology gurus said innovation in Java is gone down and Sun
Microsystems [Now Oracle] came with the Tiger release with very important changes with in java 1.5 and most important feature
was Concurrency and programming features. This is hot topic for java interviews from past few years. Interviewers are mainly
focused on java 1.5 concurrent package and they can ask how to use these changes and what are the benefits. They will focus on
how concurrency is better than synchronisation and how executors are better than old java thread implementation? How you can
avoid locks ? and What is java memory model changes for volatile etc. In investment banks we need to work on multithreaded
applications due to high volume so clear understanding of this topic is very important. This topic is key for clearing any core java
interview.
Most of these features are implemented in the new java.util.concurrent packages. There are also new concurrent data structures in
the Java Collections Framework.
Lock objects support locking idioms that simplify many concurrent applications.]
Executors define a high-level API for launching and managing threads. Executor implementations provided
by java.util.concurrent provide thread pool management suitable for large-scale applications.
Concurrent collections make it easier to manage large collections of data, and can greatly reduce the need for synchronization.]
Atomic variables have features that minimize synchronization and help avoid memory consistency errors.]
ThreadLocalRandom (in JDK 7) provides efficient generation of pseudorandom numbers from multiple threads.]
The Java programming language provides two basic synchronization idioms: synchronized methods and synchronized statements.
The more complex of the two, synchronized statements, are described in the next section. This section is about synchronized
methods.
To make a method synchronized, simply add the synchronized keyword to its declaration:
Output as PDF file has been powered by [ Universal Post Manager ] plugin from www.ProfProjects.com | Page 5/17 |
This page was exported from - TechnicalStack
Export date: Sun Mar 1 15:02:36 2020 / +0000 GMT
public class SynchronizedCounter { private int c = 0; public synchronized void increment() { c++; } public void decrement() {
synchronized(this){ c--; } } public synchronized int value() { return c; } }
If count is an instance of SynchronizedCounter, then making these methods synchronized has two effects:
- First, it is not possible for two invocations of synchronized methods on the same object to interleave. When one thread is
executing a synchronized method for an object, all other threads that invoke synchronized methods for the same object block
(suspend execution) until the first thread is done with the object.
Second, when a synchronized method exits, it automatically establishes a happens-before relationship with any subsequent
invocation of a synchronized method for the same object. This guarantees that changes to the state of the object are visible to all
threads.
Note that constructors cannot be synchronized ? using the synchronized keyword with a constructor is a syntax error. Synchronizing
constructorsdoesn't make sense, because only the thread that creates an object should have access to it while it is being constructed.
Synchronization is built around an internal entity known as the intrinsic lock or monitor lock. (The API specification often refers to
this entity simply as a "monitor.") Intrinsic locks play a role in both aspects of synchronization: enforcing exclusive access to an
object's state and establishing happens-before relationships that are essential to visibility.
Every object has an intrinsic lock associated with it. By convention, a thread that needs exclusive and consistent access to an object's
fields has to acquire the object's intrinsic lock before accessing them, and then release the intrinsic lock when it's done with them. A
thread is said to own the intrinsic lock between the time it has acquired the lock and released the lock. As long as a thread owns an
intrinsic lock, no other thread can acquire the same lock. The other thread will block when it attempts to acquire the lock.
When a thread releases an intrinsic lock, a happens-before relationship is established between that action and any subsequent
acquistion of the same lock.
Recall that a thread cannot acquire a lock owned by another thread. But a thread can acquire a lock that it already owns. Allowing a
thread to acquire the same lock more than once enables reentrant synchronization. This describes a situation where synchronized
code, directly or indirectly, invokes a method that also contains synchronized code, and both sets of code use the same lock. Without
reentrant synchronization, synchronized code would have to take many additional precautions to avoid having a thread cause itself to
block.
What is Deadlock ?
Deadlock describes a situation where two or more threads are blocked forever, waiting for each other. In below example method m1
and m2 both are taking lock of Integer and String class in different order and blocking each other for ever.
This deadlock can be solved by putting same order of lock for Integer and String class in method m1 and m2.
package com.learning.thread;
Output as PDF file has been powered by [ Universal Post Manager ] plugin from www.ProfProjects.com | Page 6/17 |
This page was exported from - TechnicalStack
Export date: Sun Mar 1 15:02:36 2020 / +0000 GMT
void m1() {
System.out.println(" m1 :");
synchronized (Blocking.class) {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
Output as PDF file has been powered by [ Universal Post Manager ] plugin from www.ProfProjects.com | Page 7/17 |
This page was exported from - TechnicalStack
Export date: Sun Mar 1 15:02:36 2020 / +0000 GMT
synchronized (String.class) {
void m2() {
System.out.println(" m2 :");
synchronized (String.class) {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
Output as PDF file has been powered by [ Universal Post Manager ] plugin from www.ProfProjects.com | Page 8/17 |
This page was exported from - TechnicalStack
Export date: Sun Mar 1 15:02:36 2020 / +0000 GMT
synchronized (Blocking.class) {
b1.m1();
b1.m2();
Output as PDF file has been powered by [ Universal Post Manager ] plugin from www.ProfProjects.com | Page 9/17 |
This page was exported from - TechnicalStack
Export date: Sun Mar 1 15:02:36 2020 / +0000 GMT
Starvation
Starvation describes a situation where a thread is unable to gain regular access to shared resources and is unable to make progress.
This happens when shared resources are made unavailable for long periods by "greedy" threads. For example, suppose an object
provides a synchronized method that often takes a long time to return. If one thread invokes this method frequently, other threads
that also need frequent synchronized access to the same object will often be blocked.
Livelock
A thread often acts in response to the action of another thread. If the other thread's action is also a response to the action of another
thread, then livelock may result. As with deadlock, livelocked threads are unable to make further progress. However, the threads are
not blocked ? they are simply too busy responding to each other to resume work. This is comparable to two people attempting to
pass each other in a corridor: Alphonse moves to his left to let Gaston pass, while Gaston moves to his right to let Alphonse pass.
Seeing that they are still blocking each other, Alphone moves to his right, while Gaston moves to his left. They're still blocking each
other, so...
An object is considered immutable if its state cannot change after it is constructed. Maximum reliance on immutable objects is
widely accepted as a sound strategy for creating simple, reliable code.
Immutable objects are particularly useful in concurrent applications. Since they cannot change state, they cannot be corrupted by
thread interference or observed in an inconsistent state.
Programmers are often reluctant to employ immutable objects, because they worry about the cost of creating a new object as
opposed to updating an object in place. The impact of object creation is often overestimated, and can be offset by some of the
efficiencies associated with immutable objects. These include decreased overhead due to garbage collection, and the elimination of
code needed to protect mutable objects from corruption.
The following subsections take a class whose instances are mutable and derives a class with immutable instances from it. In so
doing, they give general rules for this kind of conversion and demonstrate some of the advantages of immutable objects.
The following rules define a simple strategy for creating immutable objects. Not all classes documented as "immutable" follow these
rules. This does not necessarily mean the creators of these classes were sloppy ? they may have good reason for believing that
instances of their classes never change after construction. However, such strategies require sophisticated analysis and are not for
beginners.
- Don't provide "setter" methods ? methods that modify fields or objects referred to by fields.
- Make all fields final and private.
- Don't allow subclasses to override methods. The simplest way to do this is to declare the class as final. A more sophisticated
approach is to make the constructor private and construct instances in factory methods.
- If the instance fields include references to mutable objects, don't allow those objects to be changed:
- Don't provide methods that modify the mutable objects.
- Don't share references to the mutable objects. Never store references to external, mutable objects passed to the constructor;
if necessary, create copies, and store references to the copies. Similarly, create copies of your internal mutable objects when
necessary to avoid returning the originals in your methods.
Output as PDF file has been powered by [ Universal Post Manager ] plugin from www.ProfProjects.com | Page 10/17 |
This page was exported from - TechnicalStack
Export date: Sun Mar 1 15:02:36 2020 / +0000 GMT
So far, this we have focused on the low-level APIs that have been part of the Java platform from the very beginning. These APIs are
adequate for very basic tasks, but higher-level building blocks are needed for more advanced tasks. This is especially true for
massively concurrent applications that fully exploit today's multiprocessor and multi-core systems.
In this section we'll look at some of the high-level concurrency features introduced with version 5.0 of the Java platform. Most of
these features are implemented in the new java.util.concurrent packages. There are also new concurrent data structures in the Java
Collections Framework.
- Lock objects support locking idioms that simplify many concurrent applications.
- Executors define a high-level API for launching and managing threads. Executor implementations provided by
java.util.concurrent provide thread pool management suitable for large-scale applications.
- Concurrent collections make it easier to manage large collections of data, and can greatly reduce the need for
synchronization.
- Atomic variables have features that minimize synchronization and help avoid memory consistency errors.
- ThreadLocalRandom (in JDK 7) provides efficient generation of pseudorandom numbers from multiple threads
What is Executors ?
In large-scale applications, it makes sense to separate thread management and creation from the rest of the application. Objects that
encapsulate these functions are known as executors. The following subsections describe executors in detail.
Executor Interfaces
Typically, variables that refer to executor objects are declared as one of these three interface types, not with an executor class type.
Below is the example of ExecutorService using cachedThreadPool. This is using Callable instance, which does the task and return
the result to calling programme.
Output as PDF file has been powered by [ Universal Post Manager ] plugin from www.ProfProjects.com | Page 11/17 |
This page was exported from - TechnicalStack
Export date: Sun Mar 1 15:02:36 2020 / +0000 GMT
Most of the executor implementations in java.util.concurrent use thread pools, which consist of worker threads. This kind of thread
exists separately from the Runnable and Callable tasks it executes and is often used to execute multiple tasks.Using worker threads
minimizes the overhead due to thread creation. Thread objects use a significant amount of memory, and in a large-scale application,
allocating and deallocating many thread objects creates a significant memory management overhead.One common type of thread
pool is the fixed thread pool. This type of pool always has a specified number of threads running; if a thread is somehow terminated
while it is still in use, it is automatically replaced with a new thread. Tasks are submitted to the pool via an internal queue, which
holds extra tasks whenever there are more active tasks than threads.
An important advantage of the fixed thread pool is that applications using it degrade gracefully. To understand this, consider a web
server application where each HTTP request is handled by a separate thread. If the application simply creates a new thread for every
new HTTP request, and the system receives more requests than it can handle immediately, the application will suddenly stop
responding to all requests when the overhead of all those threads exceed the capacity of the system. With a limit on the number of
the threads that can be created, the application will not be servicing HTTP requests as quickly as they come in, but it will be
servicing them as quickly as the system can sustain.
A simple way to create an executor that uses a fixed thread pool is to invoke the newFixedThreadPool factory method in
java.util.concurrent.ExecutorsThis class also provides the following factory methods:
The newCachedThreadPool method creates an executor with an expandable thread pool. This executor is suitable for applications
that launch many short-lived tasks.
The newSingleThreadExecutor method creates an executor that executes a single task at a time.
Several factory methods are ScheduledExecutorService] versions of the above executors.
If none of the executors provided by the above factory methods meet your needs, constructing instances of
java.util.concurrent.ThreadPoolExecutor or java.util.concurrent.ScheduledThreadPoolExecutor will give you additional options.
What is Fork/Join ?
New in the Java SE 7 release, the fork/join framework is an implementation of the ExecutorService interface that helps you take
advantage of multiple processors. It is designed for work that can be broken into smaller pieces recursively. The goal is to use all the
available processing power to make your application wicked fast.
As with any ExecutorService, the fork/join framework distributes tasks to worker threads in a thread pool. The fork/join framework
is distinct because it uses a work-stealing algorithm. Worker threads that run out of things to do can steal tasks from other threads
that are still busy.
The center of the fork/join framework is the ForkJoinPool class, an extension of AbstractExecutorService. ForkJoinPool implements
the core work-stealing algorithm and can execute ForkJoinTasks.
Basic Use
Using the fork/join framework is simple. The first step is to write some code that performs a segment of the work. Your code should
look similar to this:
else
Output as PDF file has been powered by [ Universal Post Manager ] plugin from www.ProfProjects.com | Page 12/17 |
This page was exported from - TechnicalStack
Export date: Sun Mar 1 15:02:36 2020 / +0000 GMT
After your ForkJoinTask is ready, create one that represents all the work to be done and pass it to the invoke() method of a
ForkJoinPool instance.
The java.util.concurrent package includes a number of additions to the Java Collections Framework. These are most easily
categorized by the collection interfaces provided:
- BlockingQueue defines a first-in-first-out data structure that blocks or times out when you attempt to add to a full queue, or
retrieve from an empty queue.
- ConcurrentMap is a subinterface of java.util.Map that defines useful atomic operations. These operations remove or replace
a key-value pair only if the key is present, or add a key-value pair only if the key is absent. Making these operations atomic
helps avoid synchronization. The standard general-purpose implementation of ConcurrentMap is ConcurrentHashMap, which
is a concurrent analog of HashMap.
- ConcurrentNavigableMap is a subinterface of ConcurrentMap that supports approximate matches. The standard
general-purpose implementation of ConcurrentNavigableMap is ConcurrentSkipListMap, which is a concurrent analog of
TreeMap.
All of these collections help avoid Memory Consistency Errors by defining a happens-before relationship between an operation that
adds an object to the collection with subsequent operations that access or remove that object.
package com.learning.thread;
import java.util.concurrent.ArrayBlockingQueue;
Output as PDF file has been powered by [ Universal Post Manager ] plugin from www.ProfProjects.com | Page 13/17 |
This page was exported from - TechnicalStack
Export date: Sun Mar 1 15:02:36 2020 / +0000 GMT
String getData(){
return abq.poll();
abq.add(e);
for(String s: queue.abq){
System.out.println(s);
// Data producer
Output as PDF file has been powered by [ Universal Post Manager ] plugin from www.ProfProjects.com | Page 14/17 |
This page was exported from - TechnicalStack
Export date: Sun Mar 1 15:02:36 2020 / +0000 GMT
new Thread(
new Runnable(){
@Override
queue.setData( String.valueOf(i));
).start();
// Consumer
new Thread(
Output as PDF file has been powered by [ Universal Post Manager ] plugin from www.ProfProjects.com | Page 15/17 |
This page was exported from - TechnicalStack
Export date: Sun Mar 1 15:02:36 2020 / +0000 GMT
new Runnable(){
@Override
System.out.println(queue.getData());
).start();
Can you pass a Thread object to Executor.execute? Would such an invocation make sense? Why or why not ?
Thread implements the Runnable interface, so you can pass an instance of Thread to Executor.execute. However it doesn't make
Output as PDF file has been powered by [ Universal Post Manager ] plugin from www.ProfProjects.com | Page 16/17 |
This page was exported from - TechnicalStack
Export date: Sun Mar 1 15:02:36 2020 / +0000 GMT
sense to use Thread objects this way. If the object is directly instantiated from Thread, its run method doesn't do anything. You can
define a subclass of Thread with a useful run method ? but such a class would implement features that the executor would not use.
Output as PDF file has been powered by [ Universal Post Manager ] plugin from www.ProfProjects.com | Page 17/17 |