Java Reference
In-Depth Information
safe objects.) At the same time, synchronizing every method can lead to liveness or perform-
ance problems, as we saw in
SynchronizedFactorizer
.
2.5. Liveness and Performance
In
UnsafeCachingFactorizer
, we introduced some caching into our factoring servlet
in the hope of improving performance. Caching required some shared state, which in turn
required synchronization to maintain the integrity of that state. But the way we used syn-
chronization in
SynchronizedFactorizer
makes it perform badly. The synchroniza-
tion policy for
SynchronizedFactorizer
is to guard each state variable with the ser-
vlet object's intrinsic lock, and that policy was implemented by synchronizing the entirety of
the
service
method. This simple, coarse-grained approach restored safety, but at a high
price.
Figure 2.1. Poor Concurrency of
SynchronizedFactorizer
.
Because
service
is
synchronized
, only one thread may execute it at once. This sub-
verts the intended use of the servlet framework—that servlets be able to handle multiple re-
quests simultaneously—and can result in frustrated users if the load is high enough. If the
servlet is busy factoring a large number, other clients have to wait until the current request
is complete before the servlet can start on the new number. If the system has multiple CPUs,
processors may remain idle even if the load is high. In any case, even short-running requests,
such as those for which the value is cached, may take an unexpectedly long time because they
must wait for previous long-running requests to complete.
Figure 2.1
shows what happens when multiple requests arrive for the synchronized factoring
servlet: they queue up and are handled sequentially. We would describe this web application