Many people asked similar questions like this, but none of their answers satisfied me. The only two reordering rules that I am very sure of are as follows:
- Operations inside the synchronized block(or just call it critical section) are allowed to be reordered, as long as it confirms to the as-if-serial semantics.
- Operations(including both reads and writes) are disallowed to be moved(reordered) out of the critical section.
However, for those operations that are before or after the synchronized block, can they be moved into the critical section? For this problem, I found some contrary. For example, the cookbook said that the compiler will insert some barriers after the MonitorEnter and before the MonitorExit:
MonitorEnter
(any other needed instructions go here )
[LoadLoad] <===MB1:Inserted memory barrier
[LoadStore] <===MB2:Inserted memory barrier
(Begin of critical section)
....
(end of critical section)
[LoadStore] <===MB3:Inserted memory barrier
[StoreStore] <===MB4:Inserted memory barrier
(any other needed instructions go here )
MonitorExit
According to be above placement made by the compiler and given below pseudo code:
Load a;
Load b;
Store 1;
Store 2;
MonitorEnter
(any other needed instructions go here )
[LoadLoad] <===MB1
[LoadStore] <===MB2
(Begin of critical section)
....
(end of critical section)
[LoadStore] <===MB3
[StoreStore] <===MB4
(any other needed instructions go here )
MonitorExit
Store 3;
Store 4;
Load c;
Load d;
According to the cookbook and reordering prevention rules enforced by such XY(X is Load or Store,Y is Load or Store) memory barriers, it seems to me that valid/invalid reordering are as below:
Understanding 1: Any stores(Store 3 and Store 4 here) after the MonitorExit can NOT be moved up before MB3 and MB4, because of the existence of a LoadStore(MB3) followed by a StoreStore(MB4). That's to say stores after the MonitorExit cannot be moved into critical section. However, it can be moved up after MB4,namely the bracket area.
Understanding 2:Any loads(Load a and Load b here) before the MonitorEnter can NOT be moved down after MB2 and MB1, because of the existence of a LoadLoad(MB1) followed by a LoadLoad(MB2).That's to say loads before the MonitorEnter cannot be moved into critical sention. However, it can be moved down after MB2,namely the bracket area.
Understanding 3:Any loads(Load c and Load d here) after the MonitorExit can be moved up before the MonitorExit, including the critical section and the bracket area, but it cannot exceed the MonitorEnter.
Understanding 4: Any stores(Store 1 and Store 2 here) before the MonitorEnter can be moved down after the MonitorEnter, including the critical section and the bracket area, but it cannot exceed the MonitorExit.
However, all the above understanding or claim see to be contrary to what Jeremy Manson said in his blog, where he claimed that give below code:
x = 1;//Store
synchronized(o) {
z = z + 1;
}
y = 1//Store
Reordering that produce below code is allowed:
synchronized(o){
y = 1;//I added this comment:Store moved inside the critical section
z = z + 1;
x = 1;//I added this comment:Store moved inside the critical section
}
According to Understanding 1, "y=1" cannot be moved up inside the critical section, So I just was confused, which one is correct and complete?