Java Reference
In-Depth Information
creates a number of threads that run a given task concurrently. It uses two latches, a “starting
gate” and an “ending gate”. The starting gate is initialized with a count of one; the ending
gate is initialized with a count equal to the number of worker threads. The first thing each
worker thread does is wait on the starting gate; this ensures that none of them starts working
until they all are ready to start. The last thing each does is count down on the ending gate; this
allows the master thread to wait efficiently until the last of the worker threads has finished,
so it can calculate the elapsed time.
Why did we bother with the latches in
TestHarness
instead of just starting the threads
immediately after they are created? Presumably, we wanted to measure how long it takes to
run a task
n
times
concurrently
. If we simply created and started the threads, the threads star-
ted earlier would have a “head start” on the later threads, and the degree of contention would
vary over time as the number of active threads increased or decreased. Using a starting gate
allows the master thread to release all the worker threads at once, and the ending gate allows
the master thread to wait for the
last
thread to finish rather than waiting sequentially for each
thread to finish.
5.5.2. FutureTask
FutureTask
also acts like a latch. (
FutureTask
implements
Future
, which describes
an abstract result-bearing computation [CPJ 4.3.3].) A computation represented by a
Fu-
tureTask
is implemented with a
Callable
, the result-bearing equivalent of
Runnable
,
and can be in one of three states: waiting to run, running, or completed. Completion subsumes
all the ways a computation can complete, including normal completion, cancellation, and ex-
ception. Once a
FutureTask
enters the completed state, it stays in that state forever.
The behavior of
Future.get
depends on the state of the task. If it is completed,
get
re-
turns the result immediately, and otherwise blocks until the task transitions to the completed
state and then returns the result or throws an exception.
FutureTask
conveys the result
from the thread executing the computation to the thread(s) retrieving the result; the specifica-
tion of
FutureTask
guarantees that this transfer constitutes a safe publication of the result.
Listing 5.11. Using
CountDownLatch
for Starting and Stopping Threads in Timing Tests.