broken. There are three ways to fix it:
• Don't share the state variable across threads;
• Make the state variable immutable; or
• Use synchronization whenever accessing the state variable.
Race condition:
Check-then-act:you observe something to be true (file X doesn't exist)Check-then-act,and then take action based on that observation (create X); but in fact the observation could have become invalid
between the time you observed it and the time you acted on it (someone else created X in the meantime), causing a
problem (unexpected exception, overwritten data, file corruption).
Using Atomic Long:
@ThreadSafe
public class CountingFactorizer implements Servlet {
private final AtomicLong count = new AtomicLong(0);
public long getCount() { return count.get(); }
public void service(ServletRequest req, ServletResponse resp) {
BigInteger i = extractFromRequest(req);
BigInteger[] factors = factor(i);
count.incrementAndGet();
encodeIntoResponse(resp, factors);
}
}
To preserve state consistency, update related state variables in a single atomic operation.
Reentrancy
When a thread requests a lock that is already held by another thread, the requesting thread blocks. But because
intrinsic locks are reentrant, if a thread tries to acquire a lock that it already holds, the request succeeds. Reentrancy
means that locks are acquired on a per‐thread rather than per‐invocation basis.
Volatile Variables
The compiler and runtime are put on notice that this variable is shared.Volatile variables are not cached in registers or in caches where they are hidden from other
processors, so a read of a volatile variable always returns the most recent write by any thread.
You can use volatile variables only when all the following criteria are met:
• Writes to the variable do not depend on its current value, or you can ensure that only a single thread ever
updates the value;
• The variable does not participate in invariants with other state variables; and
• Locking is not required for any other reason while the variable is being accessed.
Locking can guarantee both visibility and atomicity; volatile variables can only guarantee visibility.
Immutable Holder for Caching a Number and its Factors.
@Immutable
class OneValueCache {
private final BigInteger lastNumber;
private final BigInteger[] lastFactors;
public OneValueCache(BigInteger i,
BigInteger[] factors) {
lastNumber = i;
lastFactors = Arrays.copyOf(factors, factors.length);
}
public BigInteger[] getFactors(BigInteger i) {
if (lastNumber == null || !lastNumber.equals(i))
return null;
else
return Arrays.copyOf(lastFactors, lastFactors.length);
}
}
Caching the Last Result Using a Volatile Reference to an Immutable Holder Object.
@ThreadSafe
public class VolatileCachedFactorizer implements Servlet {
private volatile OneValueCache cache =
new OneValueCache(null, null);
public void service(ServletRequest req, ServletResponse resp) {
BigInteger i = extractFromRequest(req);
BigInteger[] factors = cache.getFactors(i);
if (factors == null) {
factors = factor(i);
cache = new OneValueCache(i, factors);
}
encodeIntoResponse(resp, factors);
}
}
Race conditions in accessing or updating multiple related variables can be eliminated by using an immutable object to
hold all the variables. With a mutable holder object, you would have to use locking to ensure atomicity; with an
immutable one, once a thread acquires a reference to it, it need never worry about another thread modifying its state. If
the variables are to be updated, a new holder object is created, but any threads working with the previous holder still
see it in a consistent state.
To publish an object safely, both the reference to the object and the object's state must be made visible to other
threads at the same time. A properly constructed object can be safely published by:
• Initializing an object reference from a static initializer;
• Storing a reference to it into a volatile field or AtomicReference;
• Storing a reference to it into a final field of a properly constructed object; or
• Storing a reference to it into a field that is properly guarded by a lock.