Does it make sense to use flying longitude?

I sometimes use the volatile instance variable in cases where I have two threads that read / write to it and do not want the overhead (or potential risk of deadlock) to take out the lock; for example, a timer thread that periodically updates the int identifier, which is displayed as a recipient in some class:

 public class MyClass { private volatile int id; public MyClass() { ScheduledExecutorService execService = Executors.newScheduledThreadPool(1); execService.scheduleAtFixedRate(new Runnable() { public void run() { ++id; } }, 0L, 30L, TimeUnit.SECONDS); } public int getId() { return id; } } 

My question is: Given that JLS only ensures that 32-bit reads will be atomic, is there any point at ever using long-term volatile? (i.e. 64-bit).

Caution Please do not respond by saying that using volatile over synchronized is an example of preliminary optimization; I am well aware of how and when to use synchronized , but there are times when volatile is preferred. For example, when defining a Spring bean for use in a single-threaded application, I tend to use volatile instance variables, since there is no guarantee that the Spring context will initialize each bean of the property to the main thread.

+46
java multithreading concurrency volatile
Jun 14 2018-10-14
source share
3 answers

Not sure if I understood your question correctly, but JLS 8.3.1.4. volatile fields :

A field can be declared mutable, in which case the Java memory model ensures that all threads will see the consistent value for the variable ( Β§17.4 ).

and, more importantly, JLS 17.7 Non-atomic processing of double and long :

17.7 Non-atomic processing of double and long
[...]
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. Writes and reads volatile long and double values, always atomic. Writes and reads links always atomically, regardless of whether they are implemented as 32 or 64-bit values.

That is, the "whole" variable is protected by a mutable modifier, and not just by two parts. This tempts me to argue that it is even more important to use volatile for long than for int , since even reading is not atomic for long lengths / doubles.

+103
Jun 14 2018-10-14T00:
source share

This can be demonstrated with an example.

  • constantly switch two fields, one marked volatile and one not between all set bits, but all bits are cleared
  • read field values ​​in another thread
  • see that the foo field (not protected volatile) can be read in an inconsistent state, this never happens with a protected field with mutable

the code

 public class VolatileTest { private long foo; private volatile long bar; private static final long A = 0xffffffffffffffffl; private static final long B = 0; private int clock; public VolatileTest() { new Thread(new Runnable() { @Override public void run() { while (true) { foo = clock % 2 == 0 ? A : B; bar = clock % 2 == 0 ? A : B; clock++; } } }).start(); while (true) { long fooRead = foo; if (fooRead != A && fooRead != B) { System.err.println("foo incomplete write " + Long.toHexString(fooRead)); } long barRead = bar; if (barRead != A && barRead != B) { System.err.println("bar incomplete write " + Long.toHexString(barRead)); } } } public static void main(String[] args) { new VolatileTest(); } } 

Exit

 foo incomplete write ffffffff00000000 foo incomplete write ffffffff00000000 foo incomplete write ffffffff foo incomplete write ffffffff00000000 

Please note that this only happens to me when running on a 32-bit virtual machine, on a 64-bit virtual machine I could not get one error in a few minutes.

+6
Dec 22 '15 at 9:23
source share

"volatile" performs several tasks:

  • ensures that atomic writing is double / long
  • ensures that when stream A sees a change in a mutable variable made by stream B, stream A can also see all other changes made by stream B before changing to a mutable variable (consider setting the number of cells used in the array after setting the cells themselves).
  • prevents compiler optimization based on the assumption that only one thread can modify a variable (think of a narrow while (l != 0) {} .

Is there any more?

+2
Dec 22 '15 at 21:34
source share



All Articles