Java Reference
In-Depth Information
plier —in this case, we use a lambdas with empty parameter lists to invoke
startFibonacci(45) (line 39) and startFibonacci(44) (line 41). The compiler infers that
supplyAsync returns a CompletableFuture<TimeData> because method startFibonacci
returns type TimeData . Class CompletableFuture also provides static method runAsync to
execute an asynchronous task that does not return a result—this method receives a Runnable .
Getting the Asynchronous Calculations' Results
Class CompletableFuture implements interface Future , so we can obtain the asynchronous
tasks' results by calling Future method get (lines 44-45). These are blocking calls—they
cause the main thread to wait until the asynchronous tasks complete and return their results.
In our case, the results are TimeData objects. Once both tasks return, lines 46-47 pass both
TimeData objects to method calculateTime (lines 91-104) to get the total calculation
time in seconds. Then, lines 48-49 display the total calculation time for the asynchronous
Fibonacci calculations. Finally, lines 52-55 calculate and display the percentage difference
in execution time for the synchronous and asynchronous calculations.
Program Outputs
On our dual-core computer, the synchronous calculations took a total of 9.506 seconds.
Though the individual asynchronous calculations took approximately the same amount of
time as the corresponding synchronous calculations, the total time for the asynchronous
calculations was only 5.911 seconds, because the two calculations were actually performed
in parallel . As you can see in the output, the synchronous calculations took 161% more time
to complete, so asynchronous execution provided a significant performance improvement.
23.15 (Advanced) Fork/Join Framework
Java's concurrency APIs include the fork/join framework, which helps programmers par-
allelize algorithms. The framework is beyond the scope of this topic. Experts tell us that
most Java programmers will nevertheless benefit by the fork/join framework's use “behind
the scenes” in the Java API and other third party libraries. For example, the parallel capa-
bilities of Java SE 8 streams are implemented using this framework.
The fork/join framework is particularly well suited to divide-and-conquer-style algo-
rithms, such as the merge sort that we implemented in Section 19.8. Recall that the recur-
sive merge-sort algorithm sorts an array by splitting it into two equal-sized subarrays,
sorting each subarray, then merging them into one larger array. Each subarray is sorted by
performing the same algorithm on the subarray. For algorithms like merge sort, the fork/
join framework can be used to create concurrent tasks so that they can be distributed across
multiple processors and be truly performed in parallel—the details of assigning the tasks
to different processors are handled for you by the framework.
23.16 Wrap-Up
In this chapter, we presented Java's concurrency capabilities for enhancing application per-
formance on multi-core systems. You learned the differences between concurrent and par-
allel execution. We discussed that Java makes concurrency available to you through
multithreading. You also learned that the JVM itself creates threads to run a program, and
that it also can create threads to perform housekeeping tasks such as garbage collection.
 
 
 
Search WWH ::




Custom Search