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
12.1 shows our BoundedBuffer implementation, using Semaphore to implement the re-
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
and a permit is released to the availableSpaces semaphore. [2] The put operation is
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.)
Search WWH ::




Custom Search