How it works...

The following screenshot shows part of an execution of the preceding example:

The key to this example is in the FolderProcessor class. Each task processes the contents of a folder. As you know, this content has the following two kinds of elements:

  • Files
  • Other folders

If the task finds a folder, it creates another FolderProcessor object to process that folder and sends it to the pool using the fork() method. This method sends the task to the pool that will execute it if it has a free worker thread, or it can create a new one. The method returns immediately, so the task can continue processing the contents of the folder. For every file, a task compares its extension with the one it's looking for and, if they are equal, adds the name of the file to the list of results.

Once the task has processed all the contents of the assigned folder, we try to complete the current task. As we explained in the introduction of this recipe, when we try to complete a task, the code of the CountedCompleter looks for the value of the pending task counter. If this value is greater than 0, it decreases the value of that counter. On the contrary, if the value is 0, the task executes the onCompletion() method and then tries to complete its parent task. In our case, when a task is processing a folder and it finds a subfolder, it creates a new child task, launches that task using the fork() method, and increments the counter of the pending tasks. So, when a task has processed its entire content, the counter of pending tasks of the task will be equal to the number of child tasks we have launched. When we call the tryComplete() method, if the folder of the current task has subfolders, this call will decrease the number of pending tasks. Only when all its child tasks have been completed, its onCompletion() method is executed. If the folder of the current task hasn't got any subfolders, the counter of pending tasks will be zero; the onComplete() method will be called immediately, and then it will try to complete its parent task. In this way, we create a tree of tasks from top to bottom that are completed from bottom to top. In the onComplete() method, we process all the result lists of the child tasks and add their elements in the result list of the current task.

The ForkJoinPool class also allows the execution of tasks in an asynchronous way. You used the execute() method to send the three initial tasks to the pool. In the Main class, you also finished the pool using the shutdown() method and wrote information about the status and the evolution of the tasks that are running in it. The ForkJoinPool 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 to see a complete list of those methods.

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

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