The previous article covered Future and Callable in detail, and CompletionService optimizes them.

The defect of the Future

The Future uses the get method to get the result of an asynchronous task, and blocks the thread if the task hasn’t completed yet, because we need its result, so waiting is the right thing to do.

If we need to process a batch of these tasks and commit to a thread pool we end up with multiple futures, but each task may take different times to execute. Which Future’s GET should we call first? An example is shown below:

It can be seen that some tasks take a long time to execute, while the tasks behind them may take a short time to execute and have been completed in advance. However, they cannot be handled timely and can only be handled after the previous tasks are completed. This design is very unreasonable.

CompletionService to solve

Thread Java provides **CompletionService to solve this problem. You can also submit a batch of tasks to the CompletionService, which takes the first completed task. ** The usage method is as follows:

ExecutorCompletionService is CompletionService concrete implementation, we set the thread pool to ExecutorCompletionService, Can also use the submit submit tasks to ExecutorCompletionService, finally get to have completed the Future through take method.

As you can see from the above example, because the task with id equal to 3 is executed first, this task is also processed first. The first submitted task whose ID is 0 can be processed first because the sleep time is long.

ExecutorCompletionService source

From the example above you can see there are three key steps: use ExecutorCompletionService set a thread pool, submit submit tasks, take for the Future.

Look at the source code first look at its properties, check the source code to get it has two key properties:

Executor: a pool of threads that execute threads;

BlockingQueue<Future> completionQueue: Blocks the queue and saves the completed Future;

These two properties give you a pretty good idea of how it might be implemented: using thread pools to perform tasks and blocking queues to hold completed futures.

The submit method must call the thread pool’s Submit method. This is easy. The only question is how do I put the completed Future on a blocking queue?

In the last article, we learned that the class that ultimately implements an asynchronous task with a return is FutureTask, which ultimately runs FutureTask’s run method, Once the run method is complete, the finishCompletion method is called to wake up threads that are blocked by calling futureTask.get (), and the done() method is called at the end of finishCompletion, Only in FutureTask the done() method is an empty method **.

While ExecutorCompletionService is done using FutureTask () put the task in the blocking queue is realized.

QueueingFuture ExecutorCompletionService have a private inner class, it inherits FutureTask, and realizes the done () method, * * the done () method to put the task in the ExecutorCompletionService blocking the queue (so QueueingFuture is a private class). The **done() method is called only after the task has completed execution.

The illustration ExecutorCompletionService function

Figured out through the above analysis basically ExecutorCompletionService execution process, analyses the diagram below:

You can see that there are really only three steps in the entire source code:

The submit method wraps the FutureTask and saves it as a QueueingFuture property, and then submits the QueueingFuture to the thread pool.

QueueingFuture’s run method is used to execute tasks in the thread pool. The run method finally calls the done method to add the attribute FutureTask (when the task is complete) to the blocking queue.

The take method gets the FutureTask from the blocking queue;

conclusion

ExecutorCompletionService was actually quite simple one class, submit a task using the thread pool is submitted, and he created a subclass of FutureTask only used to implement the done method, add FutureTask to block at the completion of a task queue. The take method calls the take that blocks the queue to get FutureTask.

Java programmer daily study notes, such as understanding the wrong welcome to exchange discussion!