Java source code - ConcurrentHashMap read Why not lock

In a recent review prepare some interviews, occasionally pumping some bits and pieces of time before public concern number Guangyi Xia, to see what the place was missing he did not, or some knowledge to supplement the article, such as a few days ago to see an article about MySQL insert 100W of data takes a long article, the point went in to see a long absence, PreparedStatement, incidentally brushed up, the original database can not only identify pure SQL can also identify implementation plan, PreparedStatement caching mechanism utilizes SQL connection pool will turn into save up implementation plan, the parameter of placeholders (with? placeholder) way to convert plain into reusable SQL execution plan with an implementation plan can be the same but different values ​​for SQL parameters are multiplexed, thereby reducing SQL databases compiled overhead and improve performance. If Mybatis thought behind the framework, then, within it there is no similar mechanism to rinse it with the execution plan?

 

While Mybatis is a lightweight ORM framework, most of the time as long as the process in xml in SQL, but still not enough because cooked, even before the actual combat has not been this framework, it did not go to get to the bottom of this layer principle.

 

And now this paper is to discuss Java developers should (could? Maybe?) Are very familiar with one API, which is ConcurrentHashMap. From yesterday I saw an article , "Why do not ConcurrentHashMap read lock" , first talk about the article which summarizes some of the good points:

1) volatile role:

  Operating a. Volatile variables are modified to deal directly with main memory, JMM working memory is not valid in the face of volatile

  Update b. Volatile variables, JVM will issue a command to disable advanced caching all CPU, forcing the CPU to read and write variables are directly operate the main memory

  c. volatile semantics prohibited instruction reordering, and this is an important rule in the analysis of the program execution order

2) concurrently with other tools Hashtable, with the Collections.synchronizedMap () performance comparison conducted hashmap package better, because get unlocked

3) internal array of CHM members of volatile table analysis: to ensure the table visible to other threads expansion (including initialization)

4) analysis of the volatile val, next field Node node, the analysis of these fields in the "update" operation is still correct

 

Then what I think of this lack of analysis of CHM place, or that is Java Concurrency analysis does not consider thoughtful place. The following are my personal views.

First, in the analysis of concurrent Java, and can not avoid talks to several concepts: happens-before, JMM, volatile, lock, CAS. Why should happens-before on the front? ? ? Because it really is the happens-before, JMM, volatile three linking a leader. Second, it can also be directly locked and become another basis for analysis of concurrency. It can be said, happens-before're talking about Java Concurrency analysis big kill when about to enter into a dead end stage. why? Since modern CPU hundreds of billions of times per second speed of operation, even if the number of instructions that can be executed within 1 millisecond million level also, in the end who should perform the execution in a concurrent environment is very easy to point into a dead end.

The Java to define the order of execution between the two operations (Zhou Zhiming "in-depth understanding of the Java Virtual Machine Second Edition" has to happens-before, JMM, volatile more detailed explanation) using the happens-before concepts in JSR-133.

Stickers happens-before relationship several paper will be used:

(1) The program sequence rules: each operation a thread, happens-before any subsequent operation to the thread.
(2) monitor lock rules: for unlocking a lock, happens-before subsequent locking of the locks.
(. 3) volatile variable rules: to write a volatile domain, happens-before reading this field in any subsequent volatile.

(4) transitive: if A happens-before B, and B happens-before C, then A happens-before C.

(3) means the point is that after the volatile region was written, if there is a read behind the words, read all can see this update. Even after the volatile variable initialization no write, so after all the reading can read values ​​initialized (can not 0), instead of "zero value" to declare variables when JVM. (1) point in the absence of instruction reordering is established, in the presence of volatile situations that can guarantee. (2) point that is heavyweight lock synchronized, I believe will be analyzed. (4) it is also very easy to understand, and often happens-before analysis routine of concurrent important part.

 

Give happens-before a concurrent analysis example:

After thread A execution is assumed writer () method, the thread B executed Reader () method. The happens-before rule, happens-before relation established this process can be divided into three categories:
1) The program sequence rules, 1 happens-before 2; 3 happens-before 4.
2) The volatile rule, 2 happens-before 3.
3) The transfer happens-before the rule, 1 happens-before 4.

Patterning the above-described expressions happens-before relation as shown below:

 In the above example, when the analysis assumes that the thread A writer () method performs after thread B reader () method was performed, in the analysis of CHM get () method of the particle size may be smaller, you can be specific to a few lines of code on. Let's look at how to ensure CHM is get (the visibility of the bar method node).

 

Use happens-before to analyze ConcurrentHashMap get () Why not lock:

We assume CHM initial size is 16 (default), and the table is not initialized, then the table is modified as volatile, Node when it is initialized to the node 16 are the Null [] array after subsequent initialization thread can see table after the array. table initialization using CAS (sizeCtl) field to control only one thread of execution, which is the table in the initialization phase of thread safety and visibility guaranteed.

 After initialization table, assuming that there is a thread calls put (), Article N thread calls get (), which threads can see (get to) put into the val? The two pieces of code, then the same as the above example to analyze CHM concurrent put, get.

get () code snippet:

1         if ((tab = table) != null && (n = tab.length) > 0 &&          
2             (e = tabAt(tab, (n - 1) & h)) != null) {                  // 1

put () code snippet:

1             else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
2                 if (casTabAt(tab, i, null,
3                              new Node<K,V>(hash, key, value, null)))        // 2
4                     break;                   // no lock when adding to empty bin
5             }    

Followed by two code segments marked // 1 // 2. Let the threads get () to see the new Node () value must be 2 happens-before relationship 1, that new Node () must be visible thread on the premise 1 2 happens-before, that when after a call to put () thread code execution code label 2 position subsequent threads execute get () to see the value becomes null Node from the new Node (); and if 1 happens-before 2, get the thread can not see the new Node (). After Node node becomes visible thread calls get () reads the volatile val will directly read the value of main memory, so you can get to.

2 denoted by the code noted following a line of comment "no lock when adding to empty bin", meaning table [i] becomes null from the new Node () does not require locking.

PS: Here is the default annotation means feeling the CAS can guarantee visibility, that is, it is the operation of main memory. Not only is this, a lot of code with the CAS default operation of the main memory directly to ensure the visibility of the effect. Before the lower level, without taking into account this layer, so that should be implemented to find information but behind this hole to fill it.

In summary: In the table just been initialized phase, all nodes Node or null, the code only when put the new new Node () array is set to the position corresponding to the node Node fishes back when the location of the array performs get () thread visible , before this thread get () only see null node.

And when the nodes on the table array is initialized, when the latter operation then access the Node val and next, due to volatile ensures get access val and next node visibility, sharing article is also described more corresponding This paper will not repeat them.

summary

In the analysis of concurrent Java, it needs to happens-before principles as a benchmark, combined with JMM, volatile, lock, CAS and other mechanisms to analyze the program runtime code that has the "visibility" at what time.

 

Guess you like

Origin www.cnblogs.com/christmad/p/11478979.html