Search code examples
javavolatilereentrantlock

ConditionObject of ReentranentLock: fields are not decorated as volatile


Why the fields of ConditionObject are not decorated as volatile?

ConditionObject has two fields firstWaiter and lastWaiter, both are not volatile.

I known ConditionObject can only be modified by thread which hold the exclusive lock, but what if one thread modified these two fields and late another thread read them, and did not read the recently updated value due to the cpu cache?

So why fields firstWaiter and lastWaiter can keep memory consistant without volatile?

public class ConditionObject implements Condition, java.io.Serializable {
    private static final long serialVersionUID = 1173984872572414699L;

    /** These two fields are not volatile, may be modified by different thread */
    private transient ConditionNode firstWaiter;
    private transient ConditionNode lastWaiter;
}

Solution

  • A thread must own the Lock which created the Condition before it can invoke the latter's methods. If the thread does not own the lock then an exception is thrown. If you look at the rest of the implementation, you will see the values of those two fields are never used, and the two fields are never written to, unless isHeldExclusively() returns true. That method will only return true if the thread has acquired the lock, and acquiring a lock creates a happens-before relationship (see quoted documentation below).

    In other words, those two fields are properly guarded by the Lock and thus do not need to be volatile. It is no different from guarding your own state with a lock.


    From java.util.concurrent.locks.Lock:

    Memory Synchronization

    All Lock implementations must enforce the same memory synchronization semantics as provided by the built-in monitor lock, as described in Chapter 17 of The Java Language Specification:

    • A successful lock operation has the same memory synchronization effects as a successful Lock action.
    • A successful unlock operation has the same memory synchronization effects as a successful Unlock action.

    Unsuccessful locking and unlocking operations, and reentrant locking/unlocking operations, do not require any memory synchronization effects.