Is this multithreading rule with a numeric variable in the 64-bit version still true in Java 1.8 or is it deprecated?

From Goetz, Peierls, Bloch et al. 2006: Java Concurrency in Practice

3.1.2. Non-atomic 64-bit operations

When a stream reads a variable without synchronization, it can see an obsolete value, but at least it sees a value that is actually put there by some stream, and not some random value. This security guarantee is called ultra-thin security.

Interference protection for all variables, with one exception: 64-bit numeric variables (double and long) that are not declared mutable (see section 3.1.4). The Java memory model requires the retrieval and storage operations to be atomic, but for non-volatile long and double variables, the JVM is allowed to treat 64-bit read or write as two separate 32-bit operations. If reading and writing occur in different streams, it is therefore possible to read durability and return high 32 bits of one value and low 32 bits of another. [3]

Thus, even if you do not need obsolete values, it is unsafe to use shared modified long and double variables in multi-threaded programs unless they are declared mutable or not protected by a lock.

[3] When the specification of the Java virtual machine was written, many widely used processor architectures could not efficiently provide atomic 64-bit arithmetic operations.

This was written after the release of Java 5, released in 2004, with many changes aimed at simplifying multithreading and programming Concurrency. So why is it still applied? Even after ten years?

If this is only because you can run Java applications on 32-bit hardware, why is it not possible to run the JVM if necessary?

Wouldn't it be useful to be able to code multi-threaded applications with low latency without worrying about it?

+5
source share
1 answer

Is this rule a multipoint variable with a numeric variable in the 64-bit version of Java 1.8 or is it deprecated?

Yes, that’s true, refer to the Java 8 specification:
https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.7

For the purpose of the memory model of the Java programming language, one record in a non-volatile long or double value is considered as two separate records: one for each 32-bit half. This can lead to a situation where the stream sees the first 32 bits of a 64-bit value from one record, and the second 32 bits from another record.

Writing and reading volatile long and double values ​​are always atomic.

Writes and reads of links are always atomic, regardless of whether they are implemented as 32-bit or 64-bit values.


So why is it still applied?

An explanation is also contained in the specification:
https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.7

In some implementations, it may be convenient to split a single action record into a 64-bit long or double value into two write actions into adjacent 32-bit values. For efficiency, this behavior is a concrete implementation; implementation of the Java virtual machine to freely write to long and double values ​​atomically or in two parts.

Implementations of the Java virtual machine are recommended to be avoided by dividing 64-bit values ​​where possible. Programmers are encouraged to declare common 64-bit values ​​as mutable or to synchronize their programs correctly to avoid possible complications.

I think this is due to the fact that Java works on many hardware models - for example, mobile phones, routers, perhaps even refrigerators, washing machines, vacuum cleaners, etc. etc. that can be equipped with tiny 8-bit or 16-bit microprocessors. And the Java specification is common to all of them.

+6
source

All Articles