Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

why using volatile makes long and double atomic [duplicate]

I'm trying to learn the terminologies used in multi-threading in Java. So please correct me if I used wrong definition in following text:

My findings from different resources

Atomic action: According to Java doc:

In programming, an atomic action is one that effectively happens all at once. An atomic action cannot stop in the middle: it either happens completely, or it doesn't happen at all. No side effects of an atomic action are visible until the action is complete.

And that's why reading or writing to long or double variables are not atomic. Because it involves two operations, first 32-bit and the second-32 bit read/write to the variable. Also, from the paragraph above, I understand that if I used synchronized on a method, it will make the method atomic (theoretically speaking).

Volatile variables: Also from Java Doc:

This means that changes to a volatile variable are always visible to other threads. What's more, it also means that when a thread reads a volatile variable, it sees not just the latest change to the volatile, but also the side effects of the code that led up the change.

Now, also according to Effective Java 2nd Edition by Joshua Bloch, consider the following points mentioned in the book about volatile declaration:

Consider the following:

// Broken - requires synchronization!
private static volatile int nextSerialNumber = 0;

public static int generateSerialNumber() {
    return nextSerialNumber++;
}

The method’s state consists of a single atomically accessible field, nextSerialNumber, and all possible values of this field are legal. Therefore, no synchronization is necessary to protect its invariants. Still, the method won’t work properly without synchronization.

This is because nextSerialNumber++ is not atomic as it performs read, increment, write.

My summary

So if nextSerialNumber++ is not atomic, and requires synchronize. Then why the following is atomic and doesn't require synchronize?

private static volatile long someNumber = 0;

public static int setNumber(long someNumber) {
    return this.someNumber = someNumber;
}

What I don't understand is why using volatile on double or long, makes it atomic?

Because all volatile does is that it makes sure if thread B tried to read a long variable that is being written by thread A, and only 32-bit of it is written by thread A, then when thread B accesses the resource, it would get the 32-bit number that was written by thread A. And that doesn't make it atomic as the definition of the term atomic is explained in Java Doc.

like image 358
Amin Avatar asked Dec 20 '15 23:12

Amin


People also ask

Why are long and double not atomic?

It's not atomic because it's a multiple-step operation at the machine code level. That is, longs and doubles are longer than the processor's word length.

Does volatile make non atomic operation to Atomic?

The volatile keyword is used: to make non atomic 64-bit operations atomic: long and double . (all other, primitive accesses are already guaranteed to be atomic!)

What is volatile long?

int or long volatiles This means that while your main code section (e.g. your loop) reads the first 8 bits of the variable, the interrupt might already change the second 8 bits. This will produce random values for the variable.


2 Answers

What I don't understand is why using volatile on double or long, makes it atomic?

Without using the volatile keyword, you might read the first 32 bits of a double or long written by one thread, and the other 32 bits written by another thread, called word tearing, and clearly not atomic.

The volatile keyword makes sure that cannot happen. The 64 bit value you read will be a value written by one thread, not some Franken-value that is the result of writes by multiple threads. This is what it means that these types become atomic thanks to the volatile keyword.

The volatile keyword cannot make an operation like x++ atomic, regardless of the type (64 bit or 32 bit), because it's a compound operation (read + increment + write), as opposed to a simple write. The operations involved in a x++ may be interleaved by operations by other threads. The volatile keyword cannot make such compound operations atomic.

So if nextSerialNumber++ is not atomic, and requires synchronize. Then why the following is atomic and doesn't require synchronize?

private static volatile long someNumber = 0;

public static int setNumber(long someNumber) {
    return this.someNumber = someNumber;
}

nextSerialNumber++ requires synchronization because it's a compound operation, and therefore not atomic.

this.someNumber = someNumber is atomic thanks to this.someNumber being volatile, and an assignment operation is also atomic, being a single operation. Therefore there is no need to synchronize. Without volatile, this.someNumber could not be written in an atomic way, so synchronization would be necessary.

like image 154
janos Avatar answered Oct 19 '22 20:10

janos


What I don't understand is why using volatile on double or long, makes it atomic?

Here's why. Using volatile with a double or long makes them atomic because the JLS says so.

The JLS (Section 17.7) states that:

"Writes and reads of volatile long and double values are always atomic."


Note: the JLS is normative. The javadocs are non-normative as far as the language semantics are concerned. Bloch's "Effective Java" is not even a Oracle document - it is merely an (unauthorized) commentary.

like image 45
Stephen C Avatar answered Oct 19 '22 20:10

Stephen C