Java Reference
In-Depth Information
ing and not merely running slowly? Similarly, how do you test that an algorithm does
not
deadlock? How long should you wait before you declare it to have failed?
Related to liveness tests are performance tests. Performance can be measured in a number of
ways, including:
Throughput:
the rate at which a set of concurrent tasks is completed;
Responsiveness:
the delay between a request for and completion of some action (also
called
latency
); or
Scalability:
the improvement in throughput (or lack thereof) as more resources (usually
CPUs) are made available.
12.1. Testing for Correctness
Developing unit tests for a concurrent class starts with the same analysis as for a sequential
class—identifying invariants and postconditions that are amenable to mechanical checking.
If you are lucky, many of these are present in the specification; the rest of the time, writing
tests is an adventure in iterative specification discovery.
As a concrete illustration, we're going to build a set of test cases for a bounded buffer.
Listing
quired bounding and blocking.
BoundedBuffer
implements a fixed-length array-based queue with blocking
put
and
take
methods controlled by a pair of counting semaphores. The
availableItems
sem-
aphore represents the number of elements that can be
removed
from the buffer, and is ini-
tially zero (since the buffer is initially empty). Similarly,
availableSpaces
represents
how many items can be
inserted
into the buffer, and is initialized to the size of the buffer.
A
take
operation first requires that a permit be obtained from
availableItems
. This
succeeds immediately if the buffer is nonempty, and otherwise blocks until the buffer be-
comes nonempty. Once a permit is obtained, the next element from the buffer is removed
defined conversely, so that on exit from either the
put
or
take
methods, the sum of the
counts of both semaphores always equals the bound. (In practice, if you need a bounded
buffer you should use
ArrayBlockingQueue
or
LinkedBlockingQueue
rather than
rolling your own, but the technique used here illustrates how insertions and removals can be
controlled in other data structures as well.)