Java Reference
In-Depth Information
practice it makes sense to worry about the size of a
synchronized
block only when you
can move “substantial” computation or blocking operations out of it.
11.4.2. Reducing Lock Granularity
The other way to reduce the fraction of time that a lock is held (and therefore the likelihood
that it will be contended) is to have threads ask for it less often. This can be accomplished
by
lock splitting
and
lock striping
, which involve using separate locks to guard multiple in-
dependent state variables previously guarded by a single lock. These techniques reduce the
granularity at which locking occurs, potentially allowing greater scalability—but using more
locks also increases the risk of deadlock.
As a thought experiment, imagine what would happen if there was
onlyone
lock for the entire
application instead of a separate lock for each object. Then execution of all
synchronized
blocks, regardless of their lock, would be serialized. With many threads competing for the
global lock, the chance that two threads want the lock at the same time increases, resulting in
more contention. So if lock requests were instead distributed over a
larger
set of locks, there
would be less contention. Fewer threads would be blocked waiting for locks, thus increasing
scalability.
If a lock guards more than one
independent
state variable, you may be able to improve scalab-
ility by splitting it into multiple locks that each guard different variables. This results in each
lock being requested less often.
ServerStatus
in
Listing 11.6
shows a portion of the monitoring interface for a database
server that maintains the set of currently logged-on users and the set of currently executing
queries. As a user logs on or off or query execution begins or ends, the
ServerStatus
object is updated by calling the appropriate
add
or
remove
method. The two types of in-
formation are completely independent;
ServerStatus
could even be split into two separ-
ate classes with no loss of functionality.
Instead of guarding both
users
and
queries
with the
ServerStatus
lock, we can in-
stead guard each with a separate lock, as shown in
Listing 11.7
.
After splitting the lock, each
new finer-grained lock will see less locking traffic than the original coarser lock would have.
(Delegating to a thread-safe
Set
implementation for
users
and
queries
instead of us-
ing explicit synchronization would implicitly provide lock splitting, as each
Set
would use
a different lock to guard its state.)