...
Code that uses this lock behaves similar to synchronized code that uses the traditional monitor lock. ReentrantLock
provides several other capabilities, for instance, the tryLock()
method does not block waiting if another thread is already holding the lock. The class java.util.concurrent.locks.ReentrantReadWriteLock
can be used when some thread requires a lock to write information while other threads require the lock to concurrently read the information.
Noncompliant Code Example (addition, volatile fields)
In this noncompliant code example, the two fields a
and b
may be set by multiple threads, using the setValues()
method.
...
The getSum()
method may return a different sum every time it is invoked from different threads. For instance, if a
and b
currently have the value 0, and one thread calls getSum()
while another calls setValues(1, 1)
, then getSum()
might return 0, 1, or 2. Of these, the value 1 is unacceptable; it is returned when the first thread reads a
and b
, after the second thread has set the value of a
but before it has set the value of b
.
Noncompliant Code Example (addition, atomic integer fields)
The issues described in the previous noncompliant code example can also arise when the volatile variables a
and b
are replaced with atomic integers.
Code Block | ||
---|---|---|
| ||
private final AtomicInteger a = new AtomicInteger();
private final AtomicInteger b = new AtomicInteger();
public int getSum() throws ArithmeticException {
// Check for integer overflow
if( b.get() > 0 ? a.get() > Integer.MAX_VALUE - b.get() : a.get() < Integer.MIN_VALUE - b.get() ) {
throw new ArithmeticException("Not in range");
}
return a.get() + b.get(); // or, return a.getAndAdd(b.get());
}
public void setValues(int a, int b) {
this.a.set(a);
this.b.set(b);
}
|
For example, when a thread is executing setValues()
another may invoke getSum()
and retrieve an incorrect result. Furthermore, in the absence of synchronization, there are data races in the check for integer overflow.
Compliant Solution (addition)
...