Pass the volatile keyword in the interview to fully demonstrate the capabilities of the thread memory model

    During the interview, the interviewer often uses the volatile keyword to assess the candidate's ability in multi-threading. Once such questions are asked, you can take the following steps to fully understand this ability.

    1 First, explain the role of the volatile keyword through the memory model

    First, let me explain that a variable modified with volatile can directly modify the memory content, and the modified variable is visible to other threads. Then expand the description as follows.

    When multiple threads operate the same resource concurrently, the final result may be different from the expected result. Just now we have also seen this situation intuitively through the thread safety and insecurity related cases. Here we will use the thread memory structure. A detailed analysis of the causes of "inconsistent final results".

    If a thread wants to manipulate the data variable, the thread will first load the data variable into the internal memory of the thread to make a copy, and then the thread will no longer have any relationship with the data variable in the main memory, but will operate the copy variable After the operation is completed, the copy is written back to the main memory (that is, the heap memory). This process is shown in the following figure.

    Assuming that the initial value of data is 0, there are 100 threads concurrently adding 1 to it, and the expected result is 100. But in the actual operation process, suppose that the A thread and the B thread are concurrently data, where the value read by A is 0 and the value read by B is 1. When B completes the plus 1 operation in its thread internal memory (data becomes 2), it will write data back to the main memory, and then the data in the main memory is also 2.

    But after that, the A thread also completed the plus 1 operation (the data copy in the A internal thread is 1 at this time). In the subsequent write-back process, the data variable in the main memory will be set from 2 to 1, which causes The problem of inconsistent data.

    However, if the data variable is modified by a volatile variable, then the modified data variable of the A thread can be directly written back to the main memory without waiting for the ""write back"" stage, which can cause the variable to be "immediately visible to other threads" ".

2 At the same time, volatile cannot solve the problem of data inconsistency

If volatile is added before a variable, the thread will read the latest value of the variable from the main memory every time the thread uses the variable, and once a thread modifies the variable, the modification will be written back to the main memory immediately in.

Since the latest value of the variable will be read from the main memory before the operation, and it will be written back to the main memory immediately after each modification, can this solve the problem of data inconsistency in multiple threads? Through the following VolilateDemo.java code, we look at the answer to this question.

1	public class VolilateDemo extends Thread {
2		//启动1000个线程,对这个被volatile修饰的变量进行加1操作
3	    public static volatile int cnt = 0;
4		public static void add() {
5			// 延迟1毫秒,增加多线程并发抢占的概率
6			try { Thread.sleep(1);}
7	        catch (InterruptedException e) {	}
8			cnt++;//加操作
9		}
10		public static void main(String[] args) {
11			// 同时启动1000个线程,去进行加操作
12			for (int i = 0; i < 1000; i++) {
13				new Thread(new Runnable() {
14					public void run() 
15	                 {VolilateDemo.add();	}
16				}).start();
17			}
18			System.out.println("Result is " + VolilateDemo.cnt);
19		}
20	}

    In line 12 of the main function, 1000 threads are started through the for loop. From lines 13 to 16, we passed the Runnable class to define the actions of threads. After each thread is started, the add method on line 15 is called to add 1 to the volatile-modified cnt variable.

    The results of multiple runs may be different, but in most cases, the final value of cnt will be less than 1000, that is to say, variables modified with volatile cannot guarantee data consistency. In other words, volatile cannot be used as a lock. Because it cannot guarantee that the variables in the main memory will be operated by only one thread in the same time period.

3 Then talk about the role of volatile

     So what is the use of volatile? Every time a variable modified by volatile is used, it is not taken from the internal memory of each thread, but from the main memory. In this way, operations such as "creating a copy" to "writing the copy back to main memory" can be avoided, thereby improving efficiency.

    But please note that if we have read and write operations for a variable in a multithreaded environment, then do not modify it to volatile, because in order to solve the problem of data inconsistency, we will lock the variable so that the variable Only one thread can operate in a period of time, so the advantages of volatile cannot be used.

    Please keep this conclusion in mind. If a variable has only read or write operations in a multi-threaded environment, it is recommended to set it to volatile, which can improve the efficiency of multi-threaded concurrency.

4 If possible, expand to the underlying code of ConcurrentHashMap

    After saying the above content, in fact, you can already fully demonstrate your memory skills, but you can say one more thing: I have also seen the underlying source code of ConcurrentHashMap, which uses the volatile keyword.

    ConcurrentHashMap is a HashMap that supports concurrency. To put it bluntly, there will be no problem when multiple threads read and write ConcurrentHashMap objects at the same time.

    The Node object storing key-value pairs of this object is defined as follows. The val variable representing the value is volatile modified. That is to say, the operation of the ConcurrentHashMap by the A thread can be written back to the main memory immediately, so other threads can also be seen immediately. So it can support concurrency.

static class Node<K,V> implements Map.Entry<K,V> {
    final int hash;
    final K key;
    //可以看到这些都用了volatile修饰
    volatile V val;
    volatile Node<K,V> next;

    省略其它代码 
}

    When everyone extends from the volatile keyword to the underlying source code of ConcurrentHashmap, the interviewer will know that you are very experienced. I remember that when I went to interview a relatively large Internet company, I just said that, and then I passed this round of technical interviews (but there were also technical interviews with subsequent department managers).

Please pay attention to my official account: make progress together and make money together. In this official account, there will be many wonderful interview articles.

 

 

 

Guess you like

Origin blog.csdn.net/sxeric/article/details/112915422