Is there any point in using a volatile long?

前端 未结 3 1874
情深已故
情深已故 2020-12-04 13:15

I occasionally use a volatile instance variable in cases where I have two threads reading from / writing to it and don\'t want the overhead (or potential deadlo

相关标签:
3条回答
  • 2020-12-04 13:40

    This can be demonstrated by example

    • constantly toggle two fields, one marked volatile and one not between all bits set and all bits clear
    • read the field values on another thread
    • see that the foo field (not protected with volatile) can be read in an inconsistent state, this never happens to the bar field protected with volatile

    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();
        }
    }
    

    Output

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

    Note this only happens for me when running on a 32 bit VM, on 64 bit VM I couldn't get a single error in several minutes.

    0 讨论(0)
  • 2020-12-04 13:41

    Not sure if I understand your question correctly, but the JLS 8.3.1.4. volatile Fields states:

    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).

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

    17.7 Non-atomic Treatment of double and long
    [...]
    For the purposes of the Java programming language memory model, a single write to a non-volatile long or double value is treated as two separate writes: one to each 32-bit half. This can result in a situation where a thread sees the first 32 bits of a 64 bit value from one write, and the second 32 bits from another write. Writes and reads of volatile long and double values are always atomic. Writes to and reads of references are always atomic, regardless of whether they are implemented as 32 or 64 bit values.

    That is, the "entire" variable is protected by the volatile modifier, not just the two parts. This tempts me to claim that it's even more important to use volatile for longs than it is for ints since not even a read is atomic for non-volatile longs/doubles.

    0 讨论(0)
  • 2020-12-04 13:42

    "volatile" serves multiple purposes:

    • guarantees atomic writes to double/long
    • guarantees that when a thread A sees change in volatile variable made by thread B, thread A can also see all other changes made by thread B before the change to volatile variable (think setting the number of used cells in array after setting the cells themselves).
    • prevents compiler optimization based on assumption that only one thread can change the variable (think tight loop while (l != 0) {}.

    Is there more?

    0 讨论(0)
提交回复
热议问题