INDIA +91 882 616 7094 | USA +1 949 299 0280 | GERMANY +49 176 3465 1507 info@navyuginfo.com

Enhancement:

Screen Shot 2017-01-25 at 3.18.57 PM

Level 1:

  • Task And Alert service are broken down into two services i.e Task And Alert service and Email Message Service, where Task And Alert service will fetch the ‘00’ records where email has to be a shootout to the user and another Email Process Service will push the event to Internal Event Queue.

Level 2:

  1. Reentrant lock, Implementing Fairness: In a case of synchronized keyword, any thread can acquire the lock once released(as preference cannot be specified), whereas in the case of ReentrantLock fairness property is introduced, which provides a lock to longest waiting for a thread, to avoid starvation. Longest waiting for thread Email Manager Thread will get a chance to call get Next Event from Internal Event Queue.
  1. Executor Services: A pool of thread is created which will deal with writing the serializable objects to a directory, whereas Email Manager Thread will fetch the event from Internal Event Queue and will hand-over the further processing to the pool of threads and himself will return to fetch next event.

Mentioned example deals with initializing the thread, when not making use of Executors Services:

Runnable task = () -> {
String threadName = Thread.currentThread().getName();
System.out.println(“ThreadName ” + threadName);
};
task.run();
Thread thread = new Thread(task);
thread.start();
System.out.println(“Finished Working!”);

Executors Services of ThreadPoolExecutor:
Executors manage the asynchronous tasks and a pool of threads, so we don’t have to create new threads manually. All threads of the internal pool will be reused, so we can run as many concurrent tasks as a single executor service. It provides mechanisms for safely starting, closing, submitting, executing, and blocking or abrupt termination of tasks (expressed as Runnable or Callable). It extends the Executor interface and provides a thread pool feature to execute asynchronous tasks

public class WorkerThread implements Runnable {
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName());
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}}
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolExample {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(5);
for (int i = 0; i < 10; i++) {
Runnable worker = new WorkerThread(“” + i);
executor.execute(worker);
}
executor.shutdown();
while (!executor.isTerminated()) {
}
System.out.println(“Finished working with all threads”);
}
}

Executors.newFixedThreadPool(): Creates a thread pool that reuses a fixed number of threads and these 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.

Use of Runnable:

ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit(() -> {
System.out.println(“ThreadName ” + Thread.currentThread().getName());
});

Above mentioned Executor with a thread pool of size one.
// => ThreadName pool-1-thread-1
Callables are functional interfaces just like runnable but instead of being void they return a value.

Future which can be used to retrieve the actual result at a later point in time.

Use of Callable and Future:

Callable<Integer> task = () -> {
try {
return 1;
}
catch (InterruptedException e) {
throw new IllegalStateException(“task interrupted”, e);
}
};
ExecutorService executor = Executors.newFixedThreadPool(1);
Future<Integer> future = executor.submit(task);
System.out.println(“future done? ” + future.isDone());
// => result: 1

Executors provide factory methods for creating different kinds of executor services. Executors services keep listening for new tasks.

So An unused ExecutorService should be shut down to allow reclamation of its resources.

An ExecutorService provides two methods for that purpose:

  1. shutdown() waits for currently running tasks to finish
  2. shutdownNow() interrupts all running tasks and shut the executor down immediately.

try {
System.out.println(“Shutdown executor”);
executor.shutdown();
}
catch (InterruptedException e) {
System.err.println(“Interruption”);
}
finally {
executor.shutdownNow();
System.out.println(“shutdown finished”);
}

ReentrantLock:
Reentrant Lock provides enhancement over intrinsic locking capabilities(“synchronized”), with extended features such as more control on lock acquisition, by trying to get a lock with an ability to interrupt, a timeout on waiting for lock and fairness, which can be used to provide a lock to longest waiting for a thread.

public synchronized void doOperation(){
//enter synchronized block , acquire lock over this object.
function();
} // exiting synchronized block, release lock over this object.

Synchronized methods or blocks uses intrinsic locks or monitors locks. Whenever a thread tries to access a synchronized block or method, it acquires the intrinsic lock on that object. Whereas in a case of static methods, the thread acquires the lock over the class object.

Following are the limitation of the intrinsic locking mechanism:
1.) We cannot interrupt a thread, which is waiting to acquire a lock (lockInterruptibly()).
2.) Cannot acquire a lock, when a thread is not willing to wait for a mutable shared resource forever (tryLock()) or in other words, a thread doesn’t need to block infinitely, as in a case with synchronized keyword.
3.) Cannot implement non-block-structured locking disciplines, as intrinsic locks must be released in the same block in which they are acquired.

Advantages of the extrinsic lock mechanism(ReentrantLock) over intrinsic lock mechanism(synchronized):

  1. fairness, In the case of synchronized keyword any thread can acquire the lock once released(as preference can be specified), whereas, in the case of ReentrantLock fairness property, it provides a lock to longest waiting for a thread, in the case of starvation.
  1. ReentrantLock provides tryLock() method, which acquires lock only if it’s available or not held by any other thread. Which results in reducing the blocking of thread waiting for the lock.
  1. In the case of synchronized keyword, a thread can be blocked waiting for a lock, for an indefinite period of time and there was no way to control that. ReentrantLock provides a method called lockInterruptibly(), which can be used to interrupt thread when it is waiting for the lock.

References:

  1. https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/ReentrantLock.html
  2. https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ExecutorService.html