Many people asked similar questions like this, but none of their answers satisfied me. Only two reordering rules, which I am very sure, are as follows:
- Operations inside a synchronized block (or just call its critical section) are allowed to be reordered if it confirms the semantics of as-if-serial.
- Operations (including both reading and writing) are prohibited from moving (reordering) from the critical section.
However, for those operations that are before or after the synchronized block, can they be moved to the critical section? For this problem, I found the opposite. For example, cookbook said that the compiler inserts some barriers after MonitorEnter and before 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 the layout made by the compiler and the 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;
In accordance with the cookbook rules and reordering rules, which are followed by such XY memory restrictions (X - Load or Store, Y - Load or Store), it seems to me that a valid / invalid reordering looks like this:
Understanding 1: Any stores (Store 3 and Store 4 here) after MonitorExit can NOT be moved to MB3 and MB4 due to the existence of LoadStore (MB3), followed by StoreStore (MB4). That stores after MonitorExit can not be transferred to the critical section. However, it can be moved after MB4, namely the bracket area.
Understanding 2: Any loads (Load a and Load b here) before MonitorEnter CANNOT be moved down after MB2 and MB1 due to the existence of LoadLoad (MB1), followed by LoadLoad (MB2). load before MonitorEnter cannot be transferred at a critical moment. However, it can be moved down after MB2, namely in the area of ββbrackets.
Understanding 3: Any loads (Load c and Load d here) after MonitorExit can be moved to MonitorExit, including the critical section and bracket area, but it cannot exceed MonitorEnter.
Understanding 4: Any stores (Store 1 and Store 2 here) before MonitorEnter can be moved down after MonitorEnter, including the critical section and bracket area, but it cannot exceed MonitorExit.
However, all of the above understanding or claim contradicts what Jeremy Manson said on the blog , where he claimed to give the code below:
x = 1;//Store synchronized(o) { z = z + 1; } y = 1//Store
The following code release order changes are allowed:
synchronized(o){ y = 1;
According to the understanding of 1, "y = 1" cannot move inside the critical section, so I was just confused, which one is correct and complete?