Does synchronized keyword prevent reordering in Java? - java

Suppose I have the following code in Java
a = 5;
synchronized(lock){
b = 5;
}
c = 5;
Does synchronized prevent reordering? There is no dependency between a, b and c. Would assignment to a first happen then to b and then to c? If I did not have synchronized, the statements can be reordered in any way the JVM chooses right?

Locking the assignment to b will, at the very least, introduce an acquire-fence before the assignment, and a release-fence after the assignment.
This prevents instructions after the acquire-fence to be moved above the fence, and instructions before the release-fence to be moved below the fence.
Using the ↓↑ notation:
a = 5;
↓
b = 5;
↑
c = 5;
The ↓ prevents instructions from being moved above it.
The ↑ prevents instructions from being moved below it.

Does synchronized prevent reordering?
It prevents some re-ordering. You can still have re-ordering outside the synchronized block and inside the synchronized block, but not from inside a synchronized block, to outside it.
There is no dependency between a, b and c.
That makes no difference.
Would assignment to a first happen then to b and then to c?
Yes. But as has been noted, this is not guaranteed for all JVMs. (See below)
If I did not have synchronized, the statements can be reordered in any way the JVM chooses right?
Yes, by the JVM and/or the CPU instruction optimiser and/or CPU cache, but it is unlikely given there is no obvious reason to suspect that changing the order of a = 5; and b = 5; will improve performance.
What you could see is a change of visibility for the cache. i.e. another thread reading these values could see the b = 5; before a = 5; e.g. they are on different cache lines, if it is not also synchronized.

Does synchronized prevent reordering?
Partially, see below.
Would assignment to a first happen then to b and then to c?
No. As dcastro pointed out, actions can be moved into synchronized blocks. So the compiler would be allowed to generate code, that corresponds to the following statements:
synchronized (lock){
a = 5;
b = 5;
c = 5;
}
And the compiler is also allowed to reorder statements within a synchronized block, that have no dependency to each other. So the compiler can also generate code that corresponds to the following statements:
synchronized (lock){
c = 5;
b = 5;
a = 5;
}
If I did not have synchronized, the statements can be reordered in any way the JVM chooses right?
Well, I think that's the wrong question, and it's also the wrong way to think about the Java Memory Model. The Java Memory Model is not defined in terms of reorderings. Actually, it's much easier than most people think. Basically, there is only one important rule, that you can find in §17.4.5 in the Java Language Specification:
A program is correctly synchronized if and only if all sequentially consistent executions are free of data races. If a program is correctly synchronized, then all executions of the program will appear to be sequentially consistent.
In other words: If you completely ignore reorderings, and for all possible executions of the program, there is no way that two threads access the same memory location, which is neither volatile nor atomic, and at least one of the actions is a write operation, then all executions will appear, as if there are no reorderings.
In short: Avoid data races, and you will never observe a reordering.

Related

Is it true that java volatile accesses cannot be reordered?

Note
By saying that a memory access can (or cannot) be reordered I meand that it can be
reordered either by the compiler when emitting byte code byte or by the JIT when emitting
machine code or by the CPU when executing out of order (eventually requiring barriers to prevent this) with respect to any other memory access.
If often read that accesses to volatile variables cannot be reordered due to the Happens-Before relationship (HBR).
I found that an HBR exists between every two consecutive (in program order) actions of
a given thread and yet they can be reordered.
Also a volatile access HB only with accesses on the same variable/field.
What I thinks makes the volatile not reorderable is this
A write to a volatile field (§8.3.1.4) happens-before every subsequent read [of any thread]
of that field.
If there are others threads a reordering of the variables will becomes visible as in this
simple example
volatile int a, b;
Thread 1 Thread 2
a = 1; while (b != 2);
b = 2; print(a); //a must be 1
So is not the HBR itself that prevent the ordering but the fact that volatile extends this relationship with other threads, the presence of other threads is the element that prevent reordering.
If the compiler could prove that a reordering of a volatile variable would not change the
program semantic it could reorder it even if there is an HBR.
If a volatile variable is never accessed by other threads than its accesses
could be reordered
volatile int a, b, c;
Thread 1 Thread 2
a = 1; while (b != 2);
b = 2; print(a); //a must be 1
c = 3; //c never accessed by Thread 2
I think c=3 could very well be reordered before a=1, this quote from the specs
confirm this
It should be noted that the presence of a happens-before relationship between
two actions does not necessarily imply that they have to take place in that order
in an implementation. If the reordering produces results consistent with a legal
execution, it is not illegal.
So I made these simple java programs
public class vtest1 {
public static volatile int DO_ACTION, CHOOSE_ACTION;
public static void main(String[] args) {
CHOOSE_ACTION = 34;
DO_ACTION = 1;
}
}
public class vtest2 {
public static volatile int DO_ACTION, CHOOSE_ACTION;
public static void main(String[] args) {
(new Thread(){
public void run() {
while (DO_ACTION != 1);
System.out.println(CHOOSE_ACTION);
}
}).start();
CHOOSE_ACTION = 34;
DO_ACTION = 1;
}
}
In both cases both fields are marked as volatile and accessed with putstatic.
Since these are all the information the JIT has1, the machine code would be identical,
thus the vtest1 accesses will not be optimized2.
My question
Are volatile accesses really never reordered by specification or they could be3, but this is never done in practice?
If volatile accesses can never be reordered, what parts of the specs say so? and would this means that all volatile accesses are executed and seen in program order by the CPUs?
1Or the JIT can known that a field will never be accessed by other thread? If yes, how?.
2Memory barriers will be present for example.
3For example if no other threads are involved.
What the JLS says (from JLS-8.3.1.4. volatile Fields) is, in part, that
The Java programming language provides a second mechanism, volatile fields, that is more convenient than locking for some purposes.
A field may be declared volatile, in which case the Java Memory Model ensures that all threads see a consistent value for the variable (§17.4).
Which means the access may be reordered, but the results of any reordering must eventually be consistent (when accessed by another thread) with the original order. A field in a single threaded application wouldn't need locking (from volatile or synchronization).
The Java memory model provides sequential consistency (SC) for correctly synchronized programs. SC in simple terms means that if all possible executions of some program, can be explained by different executions in which all memory actions are executed in some sequential order and this order is consistent with the program order (PO) of each of the threads, then this program is consistent with these sequential executions; so it is sequential consistent (hence the name).
What this effectively means that the JIT/CPU/memory subsystem can reorder volatile writes and reads as much as it wants as long as there exists a sequential execution that could also explain the outcome of the actual execution. So the actual execution isn't that important.
If we look at the following example:
volatile int a, b, c;
Thread 1 Thread 2
a = 1; while (c != 1);
b = 1; print(b);
c = 1;
There is a happens before relation between a=1 and b=2 (PO), and a happens before relation between c=2 and c=3 (PO) and a happens before relation c=1 and c!=0 (Volatile variable rule) and a happens before relation between c!=0 and print(b) (PO).
Since the happens before relation is transitive, there is a happens before relation between a=1 and print(b). So in that sense, it can't be reordered. However, there is nobody to prove that a reordering happened, so it can still be reordered.
I'm going to be using notation from JLS §17.4.5.
In your second example, (if you'll excuse my loose notation) you have
Thread 1 ordering:
hb(a = 1, b = 2)
hb(b = 2, c = 3)
Volatile guarantees:
hb(b = 2, b != 2)
hb(a = 1, access a for print)
Thread 2 ordering:
hb(while(b != 2);, print(a))
and we have (emphasis mine)
More specifically, if two actions share a happens-before relationship,
they do not necessarily have to appear to have happened in that order
to any code with which they do not share a happens-before
relationship. Writes in one thread that are in a data race with reads
in another thread may, for example, appear to occur out of order to
those reads.
There is no happens-before relationship between c=3 and Thread 2. The implementation is free to reorder c=3 to its heart's content.
From 17.4. Memory Model of JLS
The memory model describes possible behaviors of a program. An implementation is free to produce any code it likes, as long as all resulting executions of a program produce a result that can be predicted by the memory model.
This provides a great deal of freedom for the implementor to perform a myriad of code transformations, including the reordering of actions and removal of unnecessary synchronization.

Java - happens-before relationship for monitor unlock

I have recently read http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html which clearly describes a lot of intrinsics of Java memory model. One particular excerpt got my attention namely:
The rule for a monitorexit (i.e., releasing synchronization) is that
actions before the monitorexit must be performed before the monitor is released.
Seems obvious to me, however having read http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html and happens-before definition, all I could find about the monitor unblock is when one thread unlocks the monitor that happens-before the other thread locking it again (which makes perfect sense as well). Could someone explain how JLS explains the obvious condition that all the actions within the synchronization block must happen-before the unlock operation?
FURTHER COMMENTS:
Based on a couple of responses I wanted to write up further comments to what you guys have been saying:
Reodering within a single-thread
A couple of "truths" from the source I cited:
a = new A()
if new A() involves a hundred operations, followed by assignment of address on a heap to a, compiler can simply reorder those to assign the heap address to a and then follow the usual initialization (problem from double checked locking)
synchronized{
a = 5;
}
print a;
can be changed to
synchronized{
a = 5;
print a;
}
SO we reordered monitorexit with print statement (also valid according to JLS)
Now, the simple case I mentioned:
x = 1;
y = 2;
c = x + y;
print c;
I see no reason that stops a compiler from either assigning x first or y first. There is completely nothing stopping it, as the final output is unchanged regardless of whether x is assigned first or y is. So the reordering is perfectly possible.
monitor.unlock
Based on the example with print statement being "pulled into" the synchronization block, let's try to reverse this i.e. startwing with
synchronized{
a = 5;
print a;
}
I could expect the compiler to do this:
synchronized{
a = 5;
}
print a;
Seems perfectly reasonable within the single-threaded world, YET this is definitely invalid, and against JLS (according to the cited source). Now why is that the case, if I cannot find anything within the JLS about this? and clearly the motivation about the "order of the program" is now irrelevant, since the compiler can make reoderings such as "pulling in" the statements to the synchronized block.
It's not just all actions performed within the synchronized block, it's also referring to all actions by that thread prior to the monitorexit.
Could someone explain how JLS explains the obvious condition that all
the actions within the synchronization block must happen-before the
unlock operation?
For a particular thread (and only one thread) all actions regardless of synchronized maintains program order, so it appears as if all reads and writes happen in order (we don't need a happens-before ordering in a single-thread case).
The happens-before relationship takes into account multiple threads, that is all actions happening in one thread prior to monitorexit are visible to all threads after a successive monitorenter.
EDIT to address your update.
There are particular rules the compiler must follow to re-order. The specific one in this case is demonstrated in the Can Reorder grid found here
Specifically useful entries are
First Action: Normal Load (load a; print a)
Second Action: Monitor Exit
The value here is No meaning the compiler cannot reorder two actions in which the first is a normal load and the second is monitorexit so in your case this reorder would violate the JLS.
There is a rule known as roach-motel ordering, that is read/writes can be reordered into a synchronized block but not out of it.
Maybe you missed this (§17.4.5):
If x and y are actions of the same thread and x comes before y in program order, then hb(x, y).
Combined with what you already know about happens-before, it should be clear that this implies that all actions preceding the unlock action will be visible to the other thread.
Regarding your additions to the question, if you write this:
synchronized {
a = 5;
b = 3;
}
and the compiler emits this:
synchronized{
a = 5;
}
b = 3;
then the stipulation I have quoted above is violated: now b = 3 does not happen before the lock-release. This is why it is illegal. (Note that your example with print a isn't instructive because it involves only reading + side effects not easily describable with simple variables.)

Double check locking and code reordering in Java [duplicate]

This question already has answers here:
Why is volatile used in double checked locking
(8 answers)
Closed 4 years ago.
In some article I read that double check locking is broken. As the compiler can reorder the sequence of constructors.
Ss allocate memory for an object
Then return the address to a reference variable
Then initialize the state of the object
While typically one would expect:
It should be as allocated memory for the object
then initialize the state of object
then return the address to the reference variable.
Again, when using the synchronized keyword, the code reorder never happens as per JMM specification.
Why is compiler reordering the sequence of constructor events when it is inside the synchronized() block?
I saw a lot of posts here about DCL, but I am expecting the description based on JMM and compiler reordering.
The compiler is free to reorder instructions within a synchronized block. And the compiler is free to reorder instructions before (as long as they stay before) or after (as long as they stay after) the synchronized block. However, the compiler is not free to reorder instructions across the synchronized block boundaries (block start or block end).
Thus, the construction and assignment which are wholly within the synchronized block can be reordered, and an outside viewer which has not correctly synchronized can see the assignment before the construction.
First of all:
Again when using the synchronized keyword, the code reorder never happens as per the JMM specification.
The above statement is not fully accurate. The JMM defined the happens-before relationship.
The JLS only defines the program order and happens-before order. See 17.4.5. Happens-before Order.
It has effects on the reordering of instructions. For example,
int x = 1;
synch(obj) {
y = 2;
}
int z = 3;
Now for the above piece of code, the below types of reordering are possible.
synch(obj) {
int x = 1;
y = 2;
int z = 3;
}
The above is a valid reordering.
See Roach Motels and The Java Memory Model.
synch(obj) {
int z = 3;
y = 2;
int x = 1;
}
The above is also a valid reordering.
What is not possible is that y=2 will only be executed after the lock has been acquired and before the lock is released this is what guaranteed given by JMM. Also to see the correct effects from another thread, we need to access y inside the synchronized block only.
Now I come to DCL.
See the code of DCL.
if (singleton == null)
synch(obj) {
if(singleton == null) {
singleton == new Singleton()
}
}
return singleton;
Now the problem in the above approach is:
singleton = new Singleton() is not a single instruction. But a set of instructions. It is quite possible that a singleton reference is assigned an object reference first, before fully initializing the constructor.
So if 1 happens then it's quite possible the other thread reads a singleton reference as a non null and thus is seeing a partially constructed object.
The above effects can be controlled by making a singleton as volatile which also establishes happens-before guarantees and visibility.
Why is compiler reordering the sequence of constructor events when it is inside the synchronized() block?
It would typically do this to make the code run faster.
The Java Language Specification (JLS) says that the implementation (for example, the compiler) is allowed to reorder instructions and sequences of instructions subject to certain constraints.
The problem is that the broken variants of DCL make assumptions that fall outside of what the JLS says can be made. The result is an execution that the JLS says is not well-formed. Whether this manifests itself as an actual bug / unexpected behaviour depends on the compiler version, the hardware and various other things.
But the point is that the compiler isn't doing anything wrong. The fault is in the DCL code.
I just want to add that the JIT compiler is often not reordering the events per se. what it is often doing is removing constraints on hardware-level memory read/write actions. For example, by removing the constraint that a particular memory write is flushed to main memory, you allow the hardware to defer (or even skip entirely) a slow write-to-memory, and just write to the L1 cache. By contrast, the end of a synchronized block will force the cached writes to main memory, incurring extra memory traffic and (probably) a pipeline stalls.

Is a write to a volatile a memory-barrier in Java

I recently heard in a talk that a write to a volatile triggers a memory-barrier for each variable that the thread has written to. Is that really correct? From the JLS, it seems that only the variable concerned gets flushed out, but not others. Does anybody know what is actually correct? Can one point me a concrete location in the JLS?
Yes, it will initiate a barrier. You can read more here. There are 4 types, LoadLoad LoadStore StoreStore StoreLoad.
As far as your question
From the JLS, it seems that only the variable concerned gets flushed
out, but not others. Does anybody know what is actually correct?
All writes that occur before a volatile store are visible by any other threads with the predicate that the other threads load this new store. However, writes that occur before a volatile load may or may not be seen by other threads if they do not load the new value.
For a practical example
volatile int a =0;
int b = 0;
Thread-1
b = 10;
a = 3;
Thread-2
if(a == 0){
// b can b 10 or 0
}
if(a == 3){
// b is guaranteed to be 10 (according to the JMM)
}
The reference to Volatile variables and other variables was correct. I did not realize that the transitivity of happens-before is something that must be implemented by the VM, not something that follows from the definition. I am still puzzled why something with so far-reaching consequences is not stated clearly but actually a corollary from some definition. To wrap it up: Suppose you have 4 actions like this:
thread1 thread2
a1
a2
a3
a4
where a2 is a write to a volatile variable v and a3 is a read from the same volatile variable v.
It follows from the definiton of happens-before (hb) that hb(a1,a2) and hb(a3,a4).
Also, for volatiles we have hb(a2,a3). It follows now from the required transitivity of hb that hb(a1,a3). So the write and subsequent read of the volatile variable v functions as a memory barrier.

Java memory barriers

I'm reading JSR 133 Cookbook and have the following question about memory barriers. An example of inserted memory barriers is in the book, but only writing and reading from local variables is used. Suppose I have the following variables
int a;
volatile int b;
And the code
b=a;
Do I understand correctly that this one line would produce the following instructions
load a
LoadStore membar
store b
The underlying behavior of the JVM is guaranteed only against the volatile variable. It may be possible that two separate threads may have access to different values for variable 'a' even after a thread completes evaluation of the b = a; statement. The JVM only guarantees that access to the volatile variable is serialized and has Happens-Before semantics. What this means is that the result of executing b = a; on two different threads (in the face of a "volatile" value for 'a' (ha ha)) is indeterminate because the JVM only says that the store to 'b' is serialized, it puts no guarantee on which thread has precedence.
More precisely what this means is that the JVM treats variable 'b' as having its own lock; allowing only one thread to read or write 'b' at a time; and this lock only protects access to 'b' and nothing else.
Now, this means different things under different JVMs and how this lock is actually implemented on different machine architectures may result in vastly different runtime behavior for your application. The only guarantee you should trust is what the Java reference manual says, "A field may be declared volatile, in which case the Java Memory Model ensures that all threads see a consistent value for the variable." For further review see Dennis Byrne's excellent article for some examples of how different JVM implementations deal with this issue.
Happens-Before semantics are not very interesting in the provided example because an integer primitive doesn't provide much opportunity for the kind of instruction reordering that volatile was intended (in part) to remedy. A better example is this:
private AnObjectWithAComplicatedConstructor _sampleA;
private volatile AnObjectWithAComplicatedConstructor _sampleB;
public void getSampleA() {
if (_sampleA == null) {
_sampleA = new AnObjectWithAComplicatedConstructor();
}
return _sampleA;
}
public void getSampleB() {
if (_sampleB == null) {
_sampleB = new AnObjectWithAComplicatedConstructor();
}
return _sampleB;
}
In this example field '_sampleA' has a serious problem; in a multithreaded situation it is very possible that '_sampleA' may be in the process of being initialized in one thread at the same time another thread attempts to use it leading to all sorts of sporatic and very, very difficult to duplicate bugs. To see this consider thread X to execute the 'new' byte code instruction statement of the new in getSampleA() and then stores the (yet-to-be-initialized) result in field '_sampleA'. Thread X is now paused by the JVM and thread Y starts executing getSampleA() and sees that the '_sampleA' is not null; which uninitialized value is then returned and thread Y now starts calling methods on the resulting instance causing all sorts of problems; which will, of course, only appear in production, at odd hours, and under heavy service loads.
The worse case for field _sampleB is that it may have multiple threads initializing individual instances; all but one of which will eventually be discarded. Code like this should be wrapped in a "synchronized" block but the volatile keyword will do the trick because it requires that the value finally stored in '_sampleB' has Happens-Before semantics which means that the stuff to the right of the equals sign is guaranteed to be complete when the stuff on the left hand side of the equals sign is performed.

Categories

Resources