Kyle's pages.

<–– Back

Principle of Volatile Keyword in Java

Low-level Principle

// instance is volatile variable
instance = new Singleton();

convert to assembly language:

0x01a3de1d: movb $0×0,0×1104800(%esi);
0x01a3de24: lock add1 $0×0,(%esp)

If a variable is declared to be volatile, process would execute lock command after movb when the varieble is written.

lock would do these two things in multi-core cpu:

  • Write the cache line of the current processor back to system memory

  • This operation of writing back to memory will invalidate the data cached at other cores of cpu.

Memory Semantics

When reading a valatile variable, JMM will invalidate the local memory corresponding to the thread. The thread will next read the shared variable from the memory.

Feature

  • Visibility: A read of a volatile variable always sees (any thread) the last write to the volatile variable.

  • Atomicity: The read/write of any single volatile variable is atomic, but compound operations like volatile++ are not atomic.

Atomicity in Compound Operations

Such as n ++ and n = n + 1.

Example:

public class Test {
    public volatile int inc = 0;
     
    public void increase() {
        inc++; //compound operations
    }     
    public static void main(String[] args) {
        final Test test = new Test();
        for(int i=0;i<10;i++){
            new Thread(){
                public void run() {
                    for(int j=0;j<1000;j++)
                        test.increase();
                };
            }.start();
        }    
        while(Thread.activeCount()>1)
            Thread.yield();
        System.out.println(test.inc);
    }
}

If variable inc is atomic, the result would be 10000. But in fact it is less than 10000.

There is a situation:

The inc value in memory is 10. In the inc ++ operation of thread 1, the original value of inc is read first. At this time, thread 1 is blocked, and then thread 2 performs inc ++ operation on the variable, and at this time thread 1 has not yet been written, so inc is still reading the main memory at this time, so it is still 10 (it should be 11).