Implementations in Java

Java is among the world's favorite and most admired programming languages and is used in millions of devices across the globe. There is no need to say anything further about Java, except that it's the first choice of engineers when it comes to creating application software that uses multithreaded and controlled asynchronous patterns and behaviors. Java is one of the few languages that has implemented asynchronous behavior by default in its compiler, which helps programmers to write robust, scalable, and maintainable pieces of software.

The util package of Java

Naturally, Java has more acceptability for the concept of promise and its implementation. There are many implementations in the package of java.util.concurrent, regarding promise and its implementations. We have handpicked some of the interfaces and classes that are helping out in implementing promises or nearly matching the concept.

The mechanics of Java to implement a promise

Within the java.util.concurrent package, there are a number of interfaces and classes that will help us to write concurrent and asynchronous code, but there are a few particular interfaces and libraries that are specific to this promise/future implementation.

The java.util.concurrent package is home to concurrent programming (as the name says) and is the home of few small standardized extensible frameworks. This also helps in implementing some of the core classes, which in normal conditions, are hard to work with.

The core components of java.util.concurrent

The java.util.concurrent package has many classes and components, but some of the core components that make this particular package more adaptable to work are:

The core components of java.util.concurrent

Core components of the Java util.concurrent package

Executor

Executor is a simple standardized interface, which is commonly used to define custom threaded subsystems. These subsystems include the thread pools, asynchronous I/O, and task-based lighter frameworks.

Tasks created in the thread can either be executed in "the same task-execution thread" or in a new thread; this may also be executed in the thread calling execute sequentially or concurrently. Whichever thread the execute pattern task adopts is purely based on the concrete Executor class used.

The ExecutiveService interface provides a fully stacked asynchronous tasks framework. This interface is for a number of tasks of the pool, which includes the controlled shutdown of Executor, managing of different in-pool cues, and scheduling of tasks. There are a few more associates that work with ExecutiveService to add support to delay the periodic and periodic task executing. One such associate is ScheduledExecutorService, a subinterface that works with the ExecutiveService interface in managing the delayed and periodic tasks executing whenever called upon.

There is another interface called the ExecutorService interface, which provides methods to arrange the execution of any function that is expressed as callable.

Queues

When it comes to the queue, the only thought that first emerges is the pattern of First In First Out (FIFO). Just as other languages apply this data structure in their own ways, Java treats it as an efficient and scalable thread-safe, nonblocking FIFO queue by employing the ConcurrentLinkedQueue class from its java.util.concurrent package. In the same package, five implementations support the BlockingQueue interface.

The BlockingQueue interface is a queue, which has an advanced wait mechanism. This holds the queue to further get into processing until all the previous processing is done. This also waits for the space to make the queue available when storing an element.

The five implementations of the BlockingQueue interface are listed as follows:

  • LinkedBlockingQueue
  • ArrayBlockingQueue
  • SynchronousQueue
  • PriorityBlockingQueue
  • DelayQueue

We will discuss some of these relevant implementations in the following section.

Timing

Since util is the utilities package, it has controls in the form of classes and interfaces that help engineers to make use of their daily routine stuff. One such package is the timing of a method or interface. This is to perform certain instructed operations, and eventually, they time out themselves once the operation is done.

Most of us are already aware of the importance of session creation and session timeout, especially those of us who are programmers for the Web. Session tracking is a subject in its own and doesn't really link that much from the structure of this chapter, so we will return our focus to the topic of timing.

This packing is like a timing belt of Java programs. In any engine, the role of a timing belt is to make sure that certain mechanical operations are done within a specified amount of time; it is the same as with this package. This controls the in-time and out-time of functions and also the definite/indefinite waits. The point to remember is that all these methods use the time out in every case. This helps threads define the amount of time a method spends within a thread pool and saves the actual program to perform with scalability.

Synchronizers

Java provides a low-level thread creation and execution so that programmers can easily handle and modify the thread-level control. In earlier versions, the controlling of threads was considered the hardest topic to deal with, as there was much of the manual control than automation of threads and their synchronization. At this time, Java was much more advanced in controlling multiple threads than its competing languages, but still playing with threads was a fairly hard task for Java engineers.

In the later versions of Java, this problem was considered as the most important one to find a regulation, and finally, with the emergence of version 7, the compiler has fixed most of the problems faced by engineers.

In the current version, which is version 8, five classes aid the purpose of synchronization:

Concurrent collections

The Concurrent packages provide the implementations for a multithreaded context and has the following implementations.

Since it has more specific sync facilities, some of its classes use the prefix Concurrent to highlight the additional facilitates it is providing. A few more prominent ones are:

  • ConcurrentHashMap
  • ConcurrentSkipListMap
  • ConcurrentSkipListSet
  • CopyOnWriteArrayList
  • CopyOnWriteArraySet

The virtue of concurrent collection is its safe thread, but not overlooked by a single locking mechanism, in particular. Only in the case of ConcurrentHashMap, it allows any sum of concurrent reads as well as concurrent writes. Why, then, do we use synchronized classes? The answer is that they are very useful in preventing all the access to a collection using a single lock, but it has a cost, and poorer scalability.

In other cases where multiple threads are in line to access a common collection, the current version of classes is more advisable, whereas unsynchronized locks are used when either collections are unshared or they can be accessed when holding other locks.

The implementation of promise by Java

Java implements the paradigm of promise using its promising class and interfaces. Although its asynchronous behavior is one of the core and flagship features of Java, here are the ingredients of how promise is implemented in Java:

  • Interfaces:
    • CompletionService
    • ExecutorService
    • Future
  • Classes:
    • Delayed
    • DelayQueue
    • FutureTask

CompletionService

The CompletionService interface acts as a service to make a distinction between new asynchronous tasks from the result of completed tasks. This follows a simple process in which the producer adds the tasks for execution. For the consumers, this interface takes completed tasks and processes their results in the order that they were marked as completed. This service can be used for many concurrent operations, such as managing an asynchronous I/O. The mechanism of an asynchronous I/O is the tasks that are submitted in one part of the program or set of programs or in a system, and then acted upon the different parts of the program. The submission order may be different than the order they were requested initially.

The mechanism of an asynchronous I/O is that it reads tasks and stores it in one part of the program, such as buffer.

This can be a single program (such as browser) or a set of programs (such as an operating system thread pool). The thread handler decides which thread needs to be executed first.

This interface relies on a separate executor or actually executes the tasks due to which the CompletionService interface only manages an internal completion queue. As interfaces implement, they need a class to do so, and the ExecutorCompletionService class provides such a facility.

ExecutorService

The ExecutorService interface has two main roles to perform—one is to provide methods to manage the termination of asynchronous tasks, and the other is to provide the methods that can produce a future value for tracing. This tracking can be done for either one or more asynchronous tasks.

The use of an Executor for ExecutorService:

  • ExecutorService inherits Executor, which provides the methods to manage termination and production of a future value to track the progress.
  • ExecutorService when shutdown rejects all the new tasks. They have been loaded with two different methods:
    • shutdown()
    • shutdownNow()

The shutdown() method allows the tasks in memory to conclude their states and then terminate them. Also, it prevents the memory from entering and processing it for any upcoming tasks. On the other hand, shutdownnow() doesn't give any such liberty; it just terminates whatever is in the memory, then and there. This also totally rejects the entry of new tasks in the memory by nullifying the existing thread.

Both the methods have their own significance, but since both are related to termination of existing tasks, they must be used with much care and with proper understanding of the potential consequences.

The following code snippet is taken from the original Java docs, which is available at http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ExecutorService.html:

class NetworkService implements Runnable {
  private final ServerSocket serverSocket;
  private final ExecutorService pool;

  public NetworkService(int port, int poolSize)throws IOException {
    serverSocket = new ServerSocket(port);
    pool = Executors.newFixedThreadPool(poolSize);
  }

  public void run() { // run the service
    try {
      for (;;) {
        pool.execute(new Handler(serverSocket.accept()));
      }
    } catch (IOException ex) {
      pool.shutdown();
    }
  }
}

class Handler implements Runnable {
  private final Socket socket;
  Handler(Socket socket) { this.socket = socket; }
  public void run() {
    // read and service request on socket
  }
}

The following method shuts down an ExecutorService interface in two phases: first, by calling shutdown to reject incoming tasks, and then by calling shutdownNow(), if necessary, to cancel any lingering tasks:

void shutdownAndAwaitTermination(ExecutorService pool) {
  pool.shutdown(); // Disable new tasks from being submitted
  try {
    // Wait a while for existing tasks to terminate
    if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {
      pool.shutdownNow(); // Cancel currently executing tasks
      // Wait a while for tasks to respond to being cancelled
      if (!pool.awaitTermination(60, TimeUnit.SECONDS))
        System.err.println("Pool did not terminate");
    }
  } catch (InterruptedException ie) {
    // (Re-)Cancel if current thread also interrupted
    pool.shutdownNow();
    // Preserve interrupt status
    Thread.currentThread().interrupt();
  }
}

Future

In Java, future represents the value of the result of an asynchronous computation. Methods are provided to track the status of result. These methods indicate whether the current state is waiting or not.

The catch is, you can only yield the result using get or when the computation is done.

Cancellation can be done via the cancel method; this sounds very easy to remember. Cancellation of a Future value can be done using the cancellation method.

You can also check whether the task was completed normally or cancelled by virtue of this method invocation. Once the computation is done, it cannot be cancelled; this sounds so promising to us, just like the concept of promise.

You can also use Future to cancel tasks. Although it's not a very good approach, if you want to do it, then you can declare many types of Future objects and ask the method to return null; that's it! You got your task cancelled once again. This must be done before the final computation of the tasks.

Here is the code snippet:

interface ArchiveSearcher { String search(String target); }

class App { 

  ExecutorService executor = ...ArchiveSearcher searcher = ...
  void showSearch(final String target)throws InterruptedException {
    Future<String> future
    = executor.submit(new Callable<String>() {
      public String call() {
        return searcher.search(target);
      }});
    displayOtherThings(); // do other things while searching
    try {
      displayText(future.get()); // use future
    } catch (ExecutionException ex) { cleanup(); return; }
  }
}

The FutureTask class is an implementation of Future that implements Runnable, and so may be executed by an Executor. For example, the previous construction with submit can be replaced by the following:

FutureTask<String> future =
  new FutureTask<String>(new Callable<String>() {
    public String call() {
    return searcher.search(target);
  }});
executor.execute(future);

Delay and DelayedQueue

Delay is an interface that uses a marker to mark those objects that were acted upon, after they were given a delay.

DelayedQueue is an unbounded queue that is used to collect all the objects that were delayed/expired. Since it's a queue, it must have a header element whose delay has expired long ago.

Since it's a queue and is similar to a queue data structure, it has a starting point called header and an ending point called footer. When it comes to future, the queue we are referring to here has a value, which has already expired due to the failed promise or unfulfilled promise.

If such an element was not found, will the poll return null when the expiration occurs? Well, it occurs when the method getDelay(TimeUnit.NANOSECONDS) returns the value as less than or equal to zero. The expired elements in this way cannot be removed, so they are treated as normal ones.

FutureTask

FutureTask is the cancellable asynchronous computation. This is the basic provider of Future that is loaded with methods from start of a method to cancel it. This also helps in the retrieving of the result of the computation, and since it's an implementation, the result can be extracted when the computation has been completed. Needless to mention that once the result is computed, it cannot be pulled back or changed as it's a promise.

Summing up Java and Promises.js

If we conclude the preceding discussion, it's clear that Java has a clearer approach and implementation when it comes to Promises.js. It's a mature way of handling asynchronous behavior, and especially, the way it handles multithreading is far better than what other languages have to offer. However, as every implementation has its own drawbacks, Java too has it, and it's quite acceptable since you cannot just copy and paste the theory as it is with any compiler/interpreter. There are few more supportive frameworks/libraries contributed by an open source community to add the remainder of its implementation.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.17.64.47