Java Reference
In-Depth Information
know its previous value and make sure no one else changes or uses that value while you are
in mid-update.
Like most concurrency errors, race conditions don't always result in failure: some unlucky
timing is also required. But race conditions can cause serious problems. If LazyInitRace
is used to instantiate an application-wide registry, having it return different instances from
multiple invocations could cause registrations to be lost or multiple activities to have incon-
sistent views of the set of registered objects. If UnsafeSequence is used to generate entity
identifiers in a persistence framework, two distinct objects could end up with the same ID,
violating identity integrity constraints.
2.2.3. Compound Actions
Both LazyInitRace and UnsafeCountingFactorizer contained a sequence of op-
erations that needed to be atomic , or indivisible, relative to other operations on the same state.
To avoid race conditions, there must be a way to prevent other threads from using a variable
while we're in the middle of modifying it, so we can ensure that other threads can observe or
modify the state only before we start or after we finish, but not in the middle.
Operations A and B are atomic with respect to each other if, from the perspective of a thread
executing A , when another thread executes B , either all of B has executed or none of it has.
An atomic operation is one that is atomic with respect to all operations, including itself, that
operate on the same state.
If the increment operation in UnsafeSequence were atomic, the race condition illustrated
in Figure 1.1 on page 6 could not occur, and each execution of the increment operation would
have the desired effect of incrementing the counter by exactly one. To ensure thread safety,
check-then-act operations (like lazy initialization) and read-modify-write operations (like in-
crement) must always be atomic. We refer collectively to check-then-act and read-modify-
write sequences as compound actions : sequences of operations that must be executed atom-
ically in order to remain thread-safe. In the next section, we'll consider locking , Java's builtin
mechanism for ensuring atomicity. For now, we're going to fix the problem another way, by
using an existing thread-safe class, as shown in CountingFactorizer in Listing 2.4 .
Listing 2.4. Servlet that Counts Requests Using AtomicLong .
Search WWH ::




Custom Search