The interview will ask volatile, you really will yet

Talk about your understanding of the volatile?

Do you know the underlying implementation mechanism volatile do?

volatile variables and atomic variables What is the difference?

volatile usage scenarios, you can give two examples?

Articles included in GitHub JavaKeeper , N line Internet included development of essential skills arsenal

Before a relatively detailed introduction to the Java Memory Model --JMM, JMM revolves around how to handle concurrent process visibility, and atomic ordering of these three features built up , and volatile can guarantee that two characteristics which, the following specifically discussed this interview will be asked keywords.

img

1. Concept

volatile keyword in Java, is a variable modifier is used to modify different threads access and modify variables.


2. Java Memory Model 3 properties

2.1 Visibility

Visibility is a complex property because the visibility of error will always contrary to our intuition. In general, we can not guarantee thread can perform a read operation in a timely manner to see the value of other threads written, and sometimes simply impossible. In order to ensure visibility among multiple threads of memory write operations, you must use the synchronization mechanism.

Visibility means visibility between threads, a thread modifies a state of another thread is visible . That is the result of a modification of the thread. Another thread can immediately see.

In Java volatile, synchronized and final can achieve visibility.

2.2 Atomicity

Atomicity means that when a thread is executing an operation, the middle stopper or can not be split, or the overall success or failure of the whole. For example a = 0; (a non-long and double) This operation is indivisible, then we say that the operation is atomic. Another example: a ++; this operation is actually a = a + 1; is divisible, so he is not an atomic operation. Non-thread-safe atomic operations there will be problems, we need to use synchronous technology (sychronized) to make it into an atomic operation. Operation is atomic, then we call it atomic. Providing some of the atoms of Java classes under concurrent package, AtomicInteger, AtomicLong, AtomicReference like.

In Java and synchronized in lock, unlock operation guarantee atomicity.

2.3 orderliness

Java language provides two keywords volatile and synchronized to ensure orderly, volatile because of its own with "prohibit instruction reordering" of semantics, synchronized operation between threads is by "allowing only one variable at a time in the same thread lock its operation "rule obtained, the rules determine the synchronization holding two blocks of the same object lock can only be executed serially.


3. volatile Java virtual machine is provided by a lightweight synchronization mechanism

  • Ensure visibility
  • Does not guarantee atomicity
  • Prohibition instruction rearrangement (to ensure orderly)

3.1 empty rumor, code verification

3.1.1 Visibility verification

class MyData {
    int number = 0;
    public void add() {
        this.number = number + 1;
    }
}

   // 启动两个线程,一个work线程,一个main线程,work线程修改number值后,查看main线程的number
   private static void testVolatile() {
        MyData myData = new MyData();
     
        new Thread(() -> {
            System.out.println(Thread.currentThread().getName()+"\t come in");
            try {
                TimeUnit.SECONDS.sleep(2);
                myData.add();
                System.out.println(Thread.currentThread().getName()+"\t update number value :"+myData.number);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "workThread").start();

        //第2个线程,main线程
        while (myData.number == 0){
            //main线程还在找0
        }
        System.out.println(Thread.currentThread().getName()+"\t mission is over");      
        System.out.println(Thread.currentThread().getName()+"\t mission is over,main get number is:"+myData.number);
    }
}
复制代码

Run testVolatile()method, output is as follows, you will find an infinite loop in the main thread, the main thread has been explained value is 0

workThread	 execute
workThread	 update number value :1
复制代码

Modify volatile int number = 0,, plus keyword volatile, re-run before the number, main thread gets 1 results

workThread	 execute
workThread	 update number value :1
main	 execute over,main get number is:1
复制代码

3.1.2 Verification does not guarantee atomicity

class MyData {
    volatile int number = 0;
    public void add() {
        this.number = number + 1;
    }
}

private static void testAtomic() throws InterruptedException {
  MyData myData = new MyData();

  for (int i = 0; i < 10; i++) {
    new Thread(() ->{
      for (int j = 0; j < 1000; j++) {
        myData.addPlusPlus();
      }
    },"addPlusThread:"+ i).start();
  }


  //等待上边20个线程结束后(预计5秒肯定结束了),在main线程中获取最后的number
  TimeUnit.SECONDS.sleep(5);
  while (Thread.activeCount() > 2){
    Thread.yield();
  }
  System.out.println("final value:"+myData.number);
}
复制代码

Run testAtomicdiscovery last output value, not necessarily the desired value 10000, 10000 tend to be smaller than the value.

final value:9856
复制代码

Why is this so, because i++at bytecode instructions into the time is four instructions

  • getfield Obtain the original value
  • iconst_1 The value of the stack
  • iadd Are incremented
  • putfieldThe iaddfollowing operation is written back to main memory

Such competition would exist in a multi-threaded run time, there may be a case of missing write values.

How to solve the atomic problem?

Plus synchronizedor directly Automicatoms class.

3.1.3 authentication prohibition instruction rearrangement

When the computer executes the program, in order to improve performance, often have compiler and processor instructions do rearrangement, generally divided into the following three

img

Between the processors must be considered when performing the reordering instruction data dependencies , we called as-if-serialsemantic

Single-threaded environment to ensure the final implementation of the program consistent with the results of the implementation and results of the code sequence; however multithreaded environment alternately thread execution, because the compiler optimization rearrangement exists, the variables used in the two threads can ensure consistency can not be determined the results can not be predicted.

We tend to use the following code verification volatile prohibit instruction reordering, if multi-threaded environment, `the final output is not necessarily the result of our imagination to 2, then you should both variables are set to volatile.

public class ReSortSeqDemo {

    int a = 0;
    boolean flag = false;

    public void mehtod1(){
        a = 1;
        flag = true;
    }

    public void method2(){
        if(flag){
            a = a +1;
            System.out.println("reorder value: "+a);
        }
    }
}
复制代码

volatile Achieve a ban on instruction reordering optimization, thus avoiding the phenomenon of order execution procedures in a multithreaded environment.

Another of our most common multi-threaded environment DCL(double-checked locking)singleton version of is to use the characteristics of volatile disable command rearrangement.

public class Singleton {

    private static volatile Singleton instance;
  
    private Singleton(){}
    // DCL
    public static Singleton getInstance(){
        if(instance ==null){   //第一次检查
            synchronized (Singleton.class){
                if(instance == null){   //第二次检查
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}
复制代码

Because of the presence instruction reordering, double-ended retrieval mechanism is not necessarily thread-safe.

why ?

Because: instance = new Singleton();the process of initializing the object is not really an atomic operation, which will be divided into three parts execution,

  1. For instance allocate memory
  2. Call the instance constructor to initialize the object
  3. The instance of the object points to memory space allocation (step executing the instance on which the non-null)

Step 2 and 3 data dependency relationship does not exist, the virtual machine if there is an instruction reordering optimization, the order of steps 2 and 3 can not be determined. If thread A and the first to enter the first synchronized block 3 is performed without performing 2, this time instance as has been non-null. This time thread B at the first time check, you will find instance has a non-null, it will return to its use, but this time has not been initialized instance in fact, it will naturally go wrong. So we have to restriction instruction rearrangement object instance, modified with volatile (5 JDK before using a volatile double lock detection is problematic).


4. Principle

volatile and can guarantee the visibility of the thread provides a certain orderliness, but can not guarantee atomicity. In the underlying JVM implementation is based on the memory barrier.

  • When the non-volatile read and write variables, the variables each thread memory copy start to the CPU cache. If the computer has multiple CPU, each thread can be processed on a different CPU, which means that each thread can be copied to a different CPU cache in
  • The declaration of a variable is volatile, JVM ensures that each read variables read from memory, CPU cache to skip this step, so there would be no visibility problems
    • When volatile variable is written, will add a store barrier instruction after a write operation, the working memory of a shared variable refresh back to main memory;
    • When volatile variable read operation, a load will increase the barrier instruction after a write operation, a read of the shared variable from main memory;

Get generated by the JIT compiler hsdis tool assembly instruction to look to the volatile CPU will write to do something, or the top of the single mode of embodiment can be seen

(PS: the specific assembly instructions for my Javaer south too, but we can know JVM bytecode, putstaticmeaning that the value is set to a static variable, it's here putstatic instance, and is the first line of code 17, for instance is more certain the assignment. Sure enough, as all kinds of information says, and found lock add1reportedly had to read. here you can look at these two www.jianshu.com/p/6ab7c3db1... , www.cnblogs.com/xrq730/p/70... )

When there will be more shared variables that volatile write a second line of assembler code, the sentence code means add zero to the original value , which before the addition instruction of ADDLs Lock modified. By Charles IA-32 Architectures Software Developer's Manual shows, lock prefix instruction in multi-core processors will lead to two things:

  • The current data processor cache line is written back to system memory
  • The write-back cache memory operation causes the other CPU memory address where the data is invalid

It is realized lock "to prevent instruction reordering" of volatile "memory visible" characteristics


5. usage scenarios

You can only use volatile variables instead of locking in some cases limited. For thread-safe volatile variable is ideal, you must meet the following two conditions:

  • Write to the variable does not depend on the current value
  • This variable is not included in the invariant with other variables

In fact, the need to ensure atomicity scene, do not use volatile.


5. volatile Performance

volatile read performance is almost the same consumption of normal variables, but the slower write operation, it is necessary to insert as many memory barrier instruction in native code, to ensure that the processor does not occur out of order execution.

Reference "proper use volaitle variable" a text of the words:

Difficult to make accurate and comprehensive evaluation, such as "X is always faster than Y", especially in terms of the internal operation of the JVM. (For example, in some cases JVM may be able to completely remove the locking mechanism, which makes it difficult to compare the abstract volatileand synchronized. Overhead) to say, on most of the current processor architecture, volatile read overhead is very low - almost as non-volatile read. The volatile write overhead than non-volatile write a lot more, because to ensure the visibility of the need to implement the defined memory (Memory Fence), even so, total spending remains low volatile than the lock acquisition.

volatile lock operation does not like to cause obstruction, and therefore, in the case of safe use of volatile, volatile lock can provide superior scalable features. If the number of read operations is much more than write, compared with the lock, volatile variables can often reduce the performance overhead of synchronization.

reference

"In-depth understanding of the Java Virtual Machine" tutorials.jenkov.com/java-concur... juejin.im/post/5dbfa0... "proper use of Volatile variable" www.ibm.com/developerwo...

Figure monster _b2195efd95f95e83c90c74142a4b2001_47863.png

Guess you like

Origin juejin.im/post/5e7ac6096fb9a07ce31f1230