volatile principle in-depth analysis

1, the introduction of tools (Javap)

1, javap, mainly used to help developers insights into the mechanisms of the Java compiler, the main options are:

  • -c decomposition method code, i.e. the specific method of displaying each bytecode
  • -public | protect | package | private display is used to specify the kind of level of class members
  • -verbose Displays detailed information further
    input: javap -c Test.class
D:\my-workspace\mayun\JUCDemo\out\production\JUCDemo\com\pingan>javap -c  Test.class
Compiled from "Test.java"
public class com.pingan.Test {
  static volatile java.lang.String b;

  public com.pingan.Test();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
       3: getstatic     #3                  // Field b:Ljava/lang/String;
       6: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
       9: return

  static {};
    Code:
       0: ldc           #5                  // String hello
       2: putstatic     #3                  // Field b:Ljava/lang/String;
       5: return

2、volatile

voliate type modifier is a role as a command key is volatile, to ensure that the instruction will not be omitted because of compiler optimization.

2.1 volatile characteristics

  • Achieve visibility: to ensure the visibility of the different threads of the operating variables, namely a thread modifies the value of a variable, this new value to other thread is immediately visible.
  • Orderly: the prohibition of instruction reordering.
  • Atomicity: volatile ensure only a single atomic operation, i ++ atoms of this operation can not be guaranteed;
    Here Insert Picture Description
    Here Insert Picture Description
    2.2 implementation principle of volatile
  • Visibility volatile memory variable is a memory barrier (Memory Barrier) implementation.

From the barrier, known as memory barrier is a CPU instruction.
The program is run, in order to improve the execution performance of a processor and a compiler rearranges instructions, JMM order to ensure the same result in a different compiler and the CPU, to prohibit a particular type of compiler by inserting a specific type of memory barrier ordering and reordering discouraged processor, insert a memory barrier will tell the compiler and CPU: no matter what instructions can not and this memory barrier instruction reordering.
Here Insert Picture Description
2.3 volatile application scenario
1, the conditions of use must have the volatile

  • Write operation is not dependent on the variable current value;
  • Not included in the invariant variables with other variables in the formula;

2, in order to use volatile only when the state is truly independent of other content within the program.
Mode 1: status flag
may regulate the use of volatile variables to achieve just use a Boolean flag, because the knowledge is an important one-time events occurred, such as: initialization or shutdown request

volatile boolean shutdownRequested;
......
public void shutdown() { shutdownRequested = true; }
public void doWork() { 
    while (!shutdownRequested) { 
        // do stuff
    }
}

Mode 2: Disposable Safety released
a lack of synchronization can lead to not achieve visibility, which makes determining when to write an object reference instead of the original value becomes more difficult, in the absence of synchronization, you may encounter an object reference updated value (written by another thread) and the old values of the state of the object exist.

public class BackgroundFloobleLoader {
    public volatile Flooble theFlooble;
 
    public void initInBackground() {
        // do lots of stuff
        theFlooble = new Flooble();  // this is the only write to theFlooble
    }
}
 
public class SomeOtherClass {
    public void doWork() {
        while (true) { 
            // do some stuff...
            // use the Flooble, but only if it is ready
            if (floobleLoader.theFlooble != null) 
                doSomething(floobleLoader.theFlooble);
        }
    }
}

Mode Three: independent observers
simply another mode of the safe use of volatile is regularly published observations for internal uses. For example: Suppose there is a sensor to sense the ambient temperature environment, a background thread might read once every few seconds sensor, and updates the volatile variable contains the current document, then other threads can read the variables, thus able to see at any time after the latest temperature value.

public class UserManager {
    public volatile String lastUser;
 
    public boolean authenticate(String user, String password) {
        boolean valid = passwordIsValid(user, password);
        if (valid) {
            User u = new User();
            activeUsers.add(u);
            lastUser = user;
        }
        return valid;
    }
}

Model 5: cheap read - write lock strategy

  • volatile enough to realize the function of the counter, that the inner ++ X is actually three operations (read, add, store) a simple combination. If multiple lines happened while trying to perform an incremental volatile counter operation, then it's updated value may be lost.
  • If you read much more than write operations, you can use the internal lock, and volatile variables to reduce the overhead of a common code path combination.
  • Synchronized to ensure safe use of the counter increment operation is atomic, and use volatile to ensure visibility of the current results. If the update words in infrequent cases, methods may be modified for better performance. Because of the overhead of the read path involves only volatile reads, which is usually better than the cost of a non-competitive lock acquisition.
@ThreadSafe
public class CheesyCounter {
    // Employs the cheap read-write lock trick
    // All mutative operations MUST be done with the 'this' lock held
    @GuardedBy("this") private volatile int value;
 
    public int getValue() { return value; }
 
    public synchronized int increment() {
        return value++;
    }
}

Model 6: double-check
a single case of an implementation mode, because a lot of people will ignore the volatile keyword, not because the keyword, the program can also be a very good run, but the stability of the code is not always 100%, maybe at that time, the hidden bug to deal with the storm.

class Singleton {
    private volatile static Singleton instance;
    public static Singleton getInstance() {
        if (instance == null) {
            syschronized(Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    } 
}

Recommended lazy loading elegant writing:

public class Singleton {
    
   private static class SingletonHolder{
       static  Singleton instance = new Singleton();
   }

   public static  Singleton getInstance(){
       return SingletonHolder.instance;
   }

}

Published 21 original articles · won praise 4 · Views 500

Guess you like

Origin blog.csdn.net/weixin_39617728/article/details/105058387