简体   繁体   中英

What is the extent of variable visibility effect of synchronized/volatile in Java

According to "Java Concurrency in Practice":

everything A did in or prior to a synchronized block is visible to B when it executes a synchronized block guarded by the same lock

and

The visibility effects of volatile variables extend beyond the value of the volatile variable itself. When thread A writes to a volatile variable and subsequently thread B reads that same variable, the values of all variables that were visible to A prior to writing to the volatile variable become visible to B after reading the volatile variable

what I'm not clear about is what dose it mean by everything and all variables ? Dose it mean everything literally? If we have a class like this:

class MyClassA{
  int a;
  int[] array = new int[10];
  MyClassB myClass; // a class with similar properties

  void notSyncronizedMethod(){
      // do something with a, array[3], myClass.a, myClass.array[3]
  }
  syncronized void syncronizedMethodA(){
      // update value of a, array[3], myClass.a, myClass.array[3]
  }
  syncronized void syncronizedMethodB(){
      // do something with a, array[3], myClass.a, myClass.array[3]
  }
}

if we call syncronizedMethodA() in one thread and then call syncronizedMethodB() or notSyncronizedMethod() in another thread, assume the time order is stritly garanteed, will call of syncronizedMethodB() and notSyncronizedMethod() use the latest variable value set by syncronizedMethodA() . I'm sure value of a is OK for syncronizedMethodB() , but what about elements of reference types like array[3], myClass.a or even myClass.myClass.array[3]? What about notSyncronizedMethod() with value updated by an syncronized method?

In order to figure out what visibility guarantees are provided, you need to understand the Java Memory Model a little better, and more specifically, what happens-before means in the context of the JMM. The JMM describes things that happen as actions , for example, normal reads and writes, volatile reads and writes, lock, unlock, etc.

There are a handful of rules in the JMM that establish when one action happens-before another action. The rules relevant in your case are the following:

The single thread rule : in a given thread, action A happens-before action B if A precedes B in program order.

The monitor lock rule (synchronized): An unlock of given monitor happens-before a subsequent lock on the same monitor.

It's important to know that happens-before is transitive, ie if hb(a, b) and hb(b, c), then hb(a, c).

In your example, one thread releases the monitor when exiting syncronizedMethodA() , and another thread subsequently acquires the monitor when entering syncronizedMethodB() . That's one happens-before relation. And since HB is transitive, actions performed in syncronizedMethodA() become visible for any thread that subsequently enters syncronizedMethodB() .

On the other hand, no happens-before relation exists between the release of the monitor in syncronizedMethodA() and subsequent actions performed in notSynchronizedMethod() by another thread. Therefore, there are no guarantees that the writes in syncronizedMethodA() are made visible to another thread's reads in notSynchronizedMethod() .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM