1

When acquiring a lock on instance variable, does JVM "refresh" a state of whole instance or just the state of that particular variable?

Consider implementation of following class

public class SyncObject {
    private boolean flag = false;
    private final Object lock = new Object();
    private volatile Object visibility = null;

    public void setFlag() {
        a = true;
    }

    public boolean getFlag() {
        return flag;
    }

    public void refreshLock() {
        synchronized(lock){
            ;
        }
    }

    public void refreshVisibility() {
        Object dummy = visibility;
    }
}

Two threads T1 and T2, statements are executed top to bottom

T1 -> setFlag()
T2 -> getFlag()

At this point, its obvious that T2 will most likely see the stale data as neither synchronization, nor volatile keyword was used.

However, if T2 subsequently sends messages

T2 -> refreshLock()
T2 -> getFlag()

does getFlag() method returns most up-to-date value? According to test that I've done it does.

If it's really true, could somebody please explain me why acquiring the lock on instance variable refreshes the entire owner's state and not just the state of that particular variable? I've already took a look into a JLS 17.4.4., but still can't figure it out.

Test

I used following code to test behavior described above

public class Main {

    public static void main(String[] args) {
        final SyncObject sObject = new SyncObject();

        Thread background = new Thread(() -> {
            while(!sObject.getFlag()){
                // if line below is uncommented, thread finishes in roughly 1s, otherwise it loops forever
                //sObject.refreshLock();
            }
        });

        background.start();
        TimeUnit.SECONDS.sleep(1);
        sObject.setFlag();
    }
}

Update #1

I've slightly edited SyncObject implementation and added visibility attribute as well as refreshVisibility method. If refreshLock method in test case is replaced by refreshVisibility, the behavior is the same and thread finished in about 1s.

5
  • 1
    I don't think the behavior is guaranteed unless you call refreshLock() after setFlag(). Commented May 14, 2018 at 23:52
  • Well it is exactly what I'm not sure about either. According to JavaDocs of concurrent package: An unlock (synchronized block or method exit) of a monitor happens-before every subsequent lock (synchronized block or method entry) of that same monitor. And because the happens-before relation is transitive, all actions of a thread prior to unlocking happen-before all actions subsequent to any thread locking that monitor. That being said, if I call refreshLock() on T1, subsequent lock on T2 would probably ensured consistency among threads. Commented May 15, 2018 at 0:04
  • So what are you not sure about? Commented May 15, 2018 at 0:10
  • Ah, sorry @shmosel I misinterpreted your comment - thought that you dont know whether the behavior is guaranteed. Anyway, I've updated my answer and tried to ensure visibility on thread T2 by reading volatile variable instead. Looks like it doesn't matter at all that T1 didn't write to that variable, T2 still saw most up-to-date state once volatile variable had been read. Maybe because of transitive relation of the happens-before ? Commented May 15, 2018 at 0:28
  • 3
    There's no guarantee that a thread won't see some update without proper synchronization. There's just no guarantee that it will. Commented May 15, 2018 at 0:32

1 Answer 1

1

You should have a look at the following point, that is, happen-before relationship, https://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.4.5 .

You can be sure that write operations performed by thread A are visible to thread B, if the happen before relationship holds. And that is the case when you have the threads locking the monitor in turn, or the first writing and then the other reading from a volatile variable. (plus there are other cases listed in the doc).

Also, as explained in the guide visibility is not limited to a single variable, but to every variable which changed before the "barrier".

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for answer @Daniele! I know about the fact, that if thread A unlocks a monitor and subsequently thread B locks the same monitor, all actions of a thread prior to unlocking happen-before all actions subsequent to any thread locking. The problem in my code is, that thread A didnt lock/unlock monitor. Only thread B locked/unlocked it. Check @shmosel comment below the question

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.