问题
When synchronized block execution is completed all the processor cache is flushed or only that object on which synchronized statement acted on will be flushed? In the below example when thread finished execution of method2 does data of obj2 is also flushed to the main memory?
class cls1 {
int x=10;
}
class cls2{
int y=10;
}
class cls3{
cls1 obj1;
cls2 obj2;
public void method2(){
obj2.y=10;
synchronized(obj1){
obj1.x=30;
}
}
public static void main(String[] args) {
final cls3 obj3 = new cls3();
Thread thread1 = new Thread(){
public void run(){
obj3.method2();
}
};
Thread thread2 = new Thread(){
public void run(){
System.out.println(obj3.obj1.x);
}
};
}
}
回答1:
A happens before relation is established only when the other thread also synchronizes on the lock using which the first thread updated the contents.
In this example Thread B after acquiring the lock on same object M, it will be able to see all the changes that were made before and during the synchronized block. But mind that the lock must be acquired for happens-before relationship to occur.
In your example because System.out.println(obj3.obj1.x);
is not printed inside a synchronized block, it does not guarantee happens before.
References:
- http://www.ibm.com/developerworks/library/j-jtp03304/
EDIT: Excellent answer by Peter What is the scope of memory flushed or published to various threads when using volatile and synchronized?
回答2:
When synchronized block execution is completed all the processor cache is flushed or only that object on which synchronized statement acted on will be flushed?
Quick answer: all of the dirty blocks from the processor cache are flushed.
When a thread enters a synchronized
block, it crosses a read memory-barrier which causes local copies of memory that have been updated in main memory to be flushed from the local processor memory cache.
When a thread exits a synchronized
block, it crosses a write memory-barrier and all local processor dirty blocks are written to main memory. That's not just the lock object but all dirty memory blocks.
In the below example when thread finished execution of method2 does data of obj2 is also flushed to the main memory?
Yes. When the thread exits there is also a write memory barrier that is crossed.
System.out.println(obj3.obj1.x);
This probably will not print 30
. It is important to realize that:
- There is no guarantee in your code that
thread2
will be running afterthread1
completes. Even if you startthread2
afterthread1
, race conditions may have thethread2
access ofobj1
happen beforethread1
updates it or flushes the cache to central memory. - Also, even if you guarantee that the
thread2
code does run afterthread1
finishes, you will need to make sure thatthread2
crosses a read memory barrier itself to readobj3
from main-memory and ensure thatthread2
sees the memory updates fromthread1
. That would mean makingobj3
bevolatile
or havingthread2
also enter asynchronized
block.
When you are sharing data between 2 threads it is necessary to make sure that you ensure proper order of operations and that the memory synchronization is taken into account.
回答3:
JLS doesn't speak about caches and their coherence, it uses 'happens-before' relation to establish ordering of inter-thread actions such as reads and writes to a shared memory. In your example, it's permitted to re-order obj2.y=10
so it goes after sync
block. Plus, since there's no 'happens-before' established by method entry/exit, there's no guarantee from JMM that change will become visible after method finishes.
See "Java memory model" of Java spec for detailed explanation of underlying principles.
Btw, seems you forgot to call start()
method on thread instances you've created in main
.
来源:https://stackoverflow.com/questions/38994749/cache-flush-on-synchronized-entry-exit-and-volatile-read-and-write