I came across the example below of a Java class which was claimed to be thread-safe. Could anyone please explain how it could be thread-safe? I can clearly see that the last method in the class is not being guarded against concurrent access of any reader thread. Or, am I missing something here?
public class Account {
private Lock lock = new ReentrantLock();
private int value = 0;
public void increment() {
lock.lock();
value++;
lock.unlock();
}
public void decrement() {
lock.lock();
value--;
lock.unlock();
}
public int getValue() {
return value;
}
}
The short answer :
By definition,Account
is a thread-safe class even though the geValue
method is not guarded
The long answer
From Java Concurrency in practice a class is said to be thread safe when :
No set of operations performed sequentially or concurrently on instances of a thread-safe class can cause an instance to be in an invalid state.
Since the the getValue
method will not result in the Account
class being in an invalid state at any given time, your class is said to be thread safe.
The documentation for Collections#synchronizedCollection resonates this sentiment :
Returns a synchronized (thread-safe) collection backed by the specified collection. In order to guarantee serial access, it is critical that all access to the backing collection is accomplished through the returned collection. It is imperative that the user manually synchronize on the returned collection when iterating over it:
Collection c = Collections.synchronizedCollection(myCollection); ... synchronized (c) { Iterator i = c.iterator(); // Must be in the synchronized block while (i.hasNext()) foo(i.next()); }
Notice how the documentation says that the collection (which is an object of an inner class named SynchronizedCollection
in the Collections
class) is thread-safe and yet asks the client code to guard the collection while iterating over it. Infact, the iterator
method in SynchronizedCollection
is not synchronized
. This is very similar to your example where Account
is thread-safe but client code still needs to ensure atomicity when calling getValue
.