The volatile key word and memory consistency errors

前端 未结 4 731
谎友^
谎友^ 2021-02-09 11:28

In the oracle Java documentation located here, the following is said:

Atomic actions cannot be interleaved, so they can be used without f

4条回答
  •  醉话见心
    2021-02-09 11:50

    What do they mean by "reduces the risk"?

    Atomicity is one issue addressed by the Java Memory Model. However, more important than Atomicity are the following issues:

    • memory architecture, e.g. impact of CPU caches on read and write operations
    • CPU optimizations, e.g. reordering of loads and stores
    • compiler optimizations, e.g. added and removed loads and stores

    The following listing contains a frequently used example. The operations on x and y are atomic. Still, the program can print both lines.

    int x = 0, y = 0;
    
    // thread 1
    x = 1
    if (y == 0) System.out.println("foo");
    
    // thread 2
    y = 1
    if (x == 0) System.out.println("bar");
    

    However, if you declare x and y as volatile, only one of the two lines can be printed.


    How is a memory consistency error still possible when using volatile?

    The following example uses volatile. However, updates might still get lost.

    int x = 0;
    
    // thread 1
    x += 1;
    
    // thread 2
    x += 1;
    

    Would it be true to say that the only effect of placing volatile on a non-double, non-long primitive is to enable the "happens-before" relationship with subsequent reads from other threads?

    Happens-before is often misunderstood. The consistency model defined by happens-before is weak and difficult to use correctly. This can be demonstrated with the following example, that is known as Independent Reads of Independent Writes (IRIW):

    volatile int x = 0, y = 0;
    
    // thread 1
    x = 1;
    
    // thread 2
    y = 1;
    
    // thread 3
    if (x == 1) System.out.println(y);
    
    // thread 4
    if (y == 1) System.out.println(x);
    

    Only with happens-before, two 0s would be valid result. However, that's apparently counter-intuitive. For that reason, Java provides a stricter consistency model, that forbids this relativity issue, and that is known as sequential consistency. You can find it in sections §17.4.3 and §17.4.5 of the Java Language Specification. The most important part is:

    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 (§17.4.3).

    That means, volatile gives you more than happens-before. It gives you sequential consistency if used for all conflicting accesses (§17.4.3).

提交回复
热议问题