How it works...

In this example, you created a ForkJoinPool object and a subclass of the ForkJoinTask class that you executed in the pool. To create the ForkJoinPool object, you used the constructor without arguments, so it will be executed with its default configuration. It creates a pool with a number of threads equal to the number of processors of the computer. When the ForkJoinPool object is created, those threads are created and they wait in the pool until some tasks arrive for their execution.

Since the Task class doesn't return a result, it extends the RecursiveAction class. In the recipe, you used the recommended structure for the implementation of the task. If the task has to update more than 10 products, it divides that set of elements into two blocks, creates two tasks, and assigns a block to each task. You used the first and last attributes in the Task class to know the range of positions that this task has to update in the list of products. You used the first and last attributes to use only one copy of the product list and not create different lists for each task.

To execute the subtasks that a task creates, it calls the invokeAll() method. This is a synchronous call, and the task waits for the finalization of the subtasks before continuing (potentially finishing) its execution. While the task is waiting for its subtasks, the worker thread that was executing it takes another task waiting for execution and executes it. With this behavior, the fork/join framework offers more efficient task management than the Runnable and Callable objects themselves.

The invokeAll() method of the ForkJoinTask class is one of the main differences between the Executor and the fork/join framework. In the Executor framework, all the tasks have to be sent to the executor while in this case, the tasks include methods to execute and control the tasks inside the pool. You used the invokeAll() method in the Task class, which extends the RecursiveAction class, which in turn extends the ForkJoinTask class.

You sent a unique task to the pool to update all the lists of products using the execute() method. In this case, it's an asynchronous call, and the main thread continues its execution.

You used some methods of the ForkJoinPool class to check the status and the evolution of the tasks that are running. The class includes more methods that can be useful for this purpose. See the Monitoring a fork/join pool recipe in Chapter 9, Testing Concurrent Applications for a complete list of those methods.

Finally, like with the Executor framework, you should finish ForkJoinPool using the shutdown() method.

The following screenshot shows part of an execution of this example:

You can see the tasks finishing their work and the price of the products updated.

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

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