Java Reference
In-Depth Information
calculation time for the sequential
LongStream
and just 22% of the time required to per-
form the five operations separately.
Interface
Runnable
provides only the most basic functionality for multithreaded program-
ming. In fact, this interface has limitations. Suppose a
Runnable
is performing a long cal-
culation and the application wants to retrieve the result of that calculation. The
run
method cannot return a value, so
shared mutable data
would be required to pass the value
back to the calling thread. As you now know, this would require thread synchronization.
The
Callable
interface (of package
java.util.concurrent
) fixes this limitation. The in-
terface declares a single method named
call
which returns a value representing the result
of the
Callable
's task—such as the result of a long running calculation.
An application that creates a
Callable
likely wants to run it concurrently with other
Runnable
s and
Callable
s.
ExecutorService
method
submit
executes its
Callable
argu-
ment and returns an object of type
Future
(of package
java.util.concurrent
), which
represents the
Callable
's future result. The
Future
interface
get
method
blocks
the calling
thread, and waits for the
Callable
to complete and return its result. The interface also
provides methods that enable you to cancel a
Callable
's execution, determine whether the
Callable
was cancelled and determine whether the
Callable
completed its task.
Executing Aysnchronous Tasks with
CompletableFuture
Java SE 8 introduces class
CompletableFuture
(package
java.util.concurrent
), which
implements the
Future
interface and enables you to
asynchronously
execute
Runnable
s that
perform tasks or
Supplier
s that return values. Interface
Supplier
, like interface
Callable
,
is a functional interface with a single method (in this case,
get
) that receives no arguments
and returns a result. Class
CompletableFuture
provides many additional capabilities that for
advanced programmers, such as creating
CompletableFuture
s without executing them im-
mediately, composing one or more
CompletableFuture
s so that you can wait for any or all
of them to complete, executing code after a
CompletableFuture
completes and more.
Figure 23.30 performs two long-running calculations sequentially, then performs
them again asynchronously using
CompletableFuture
s to demonstrate the performance
improvement from asynchronous execution on a multi-core system. For demonstration
purposes, our long-running calculation is performed by a recursive
fibonacci
method
(lines 73-79; similar to the one presented in Section 18.5). For larger Fibonacci values,
the recursive implementation can require
significant
computation time—in practice, it's
much faster to calculate Fibonacci values using a loop.
1
// FibonacciDemo.java
2
// Fibonacci calculations performed synchronously and asynchronously
3
import
java.time.Duration;
4
import
java.text.NumberFormat;
5
import
java.time.Instant;
6
7
8
import
java.util.concurrent.CompletableFuture;
import
java.util.concurrent.ExecutionException;
Fig. 23.30
|
Fibonacci calculations performed synchronously and asynchronously. (Part 1 of 4.)