Question

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?

Was it helpful?

Solution 2

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.

OTHER TIPS

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?

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top