Search code examples
javamultithreadingconcurrencyhappens-before

Happens-before and volatile variable


Following are just three "happens-before" rules of JMM. I am not listing the other rules as my question is related to these three rules only.

  • Monitor lock rule. An unlock on a monitor lock happens before every subsequent lock on that same monitor lock.
  • Thread start rule. A call to Thread.start on a thread happens before every action in the started thread.
  • Interruption rule. A thread calling interrupt on another thread happens before the interrupted thread detects the interrupt (either by having InterruptedException thrown, or invoking isInterrupted or interrupted).

Questions

  1. 1st rule question - Let's say two threads A and B have synchronized blocks of code. Does the first rule mean that any variable set in a synchronized block in thread A, will be visible to the code in synchronized block of thread B, even if the variable is NOT declared as volatile?

  2. 2nd rule question - Let's say a thread A starts a thread B. Does the second rule mean that any variable set in a parent thread before calling start() will be visible to thread B even if the variable is NOT declared as volatile?

  3. 3rd rule question - Let's say a thread A interrupts a thread B. Does the third rule mean that any variable set in thread A before interrupting thread B will be visible to thread B after the interrupt is detected, even if the variable is not declared as volatile?

Finally, one more question:

  1. In BlockingQueue documentation, it is said,

    Memory consistency effects: As with other concurrent collections, actions in a >thread prior to placing an object into a BlockingQueue happen-before actions >subsequent to the access or removal of that element from the BlockingQueue in >another thread.

Does this mean any variable set in a thread A before enqueuing an object in the blocking queue will be visible to thread B after dequeuing the object from the queue, even if the variable is NOT declared as volatile?

Basically through the above questions, I am trying to understand if the memory flush happens after these events such that the variables need not be declared as volatile in these cases.


Solution

  • 1st rule question - Let's say two threads A and B have synchronized blocks of code.

    Threads don't have code. Threads execute code.

    Does the first rule mean that any variable set in a synchronized block in thread A, will be visible to the code in synchronized block of thread B, even if the variable is NOT declared as volatile?

    Yes, Suppose we have:

    private int i;
    private final Object lock = new Object();
    
    void foobar(...) {
        ...
        synchronized(lock) {
            i = ...;
        }
    }
    
    int getI() {
        synchronized(lock) {
            return i;
        }
    }
    

    If thread A calls foobar(), and then thread B subsequently calls getI(), then thread B will get the new value of i.

    But note! My example above does not include any way for you to prove which call actually happened first. If your program depends on those calls to happen in a particular order, then it's going to need more than just a mutex: It's going to need some means to make thread B wait() for thread A to perform the update.


    2nd rule question - Let's say a thread A starts a thread B. Does the second rule mean that any variable set in a parent thread before calling start() will be visible to thread B even if the variable is NOT declared as volatile?

    Yes, that's what it means.

    3rd rule question...

    Yes again.

    1. ... BlockingQueue ...

    Yes again.


    ...Through the above questions, I am trying to understand if the memory flush happens after these events such that...

    Don't even think about "memory flush". That is not part of the Java language: If it happens, it's an implementation detail, and you don't need to worry about it unless you are implementing a JVM.

    The only concept you need to worry about is the "happens before".

    Whenever the JLS says that A happens before B, it means that if A happens in thread 1, and B happens in thread 2, and you can prove that A actually did happen before B in real-time, then any field that was updated by thread 1 before A happened will be guaranteed visible in thread 2 after B happens.