Why use ConcurrentHashMap?
ConcurrentHashMap
is a thread-safe program under the JUC package.HashMap
class, we all know that multi-threaded scenarios are going to use theConcurrentHashMap
in place ofHashMap
use, ever wondered why it can't be usedHashMap
Why does it work?ConcurrentHashMap
What about it? I'll take you through some of the details by walking through the source code!
HashMap
map
A type of array.JDK1.8
hit the nail on the headHashMap
in the form of arrays + linked lists/red-black trees, not too much explanation here
When we are executing a multithreaded task, if the resource being operated on is theHashMap
type can lead to concurrency exceptions in the program, as shown in Figure
check on sthnextNode
The reason for going to the source code in this method is obvious, as shown in Figure
So what do the two variables in the if judgment do, and why should they throw an exception if they are not the same?
First, let's look at what we've learned from creating theHashmap
What was done between the time the variable was created and the time the exception was thrown?
The code for the whole process is as follows
public static void main(String[] args) {
HashMap<String,String> map = new HashMap<>();
for (int i = 0;i < 20; i++){
new Thread(()-> {
(().getName(),new Date().toString());
(map);
},(i)).start();
}
}
Let's click in.HashMap
can be seen in the constructor method of the method, which is only given hereloadFactor
This variable an initial value, which we know as the loading factor 0.75
Let's go over what the put method does.
put
->putVal
When we click on it, we see that this is the first variable in the if judgment we saw above. If we go to the definition of the variable, we can see that it's an int and not assigned a value.
We can get an initial conclusion by this, when we execute the put method every time, this value will perform a +1 operation
As you can see below there is another one calledafterNodeInsertion
method, we clicked on it and found that it was an empty method, and then read the comments on it, which probably meant to give theLinkedHashMap
The methods of the callbacks provided by theLinkedHashMap
beHashMap
A subclass of
Then we tapprintln
methodologies
println->valueOf->toString
Find usHashMap
rewrittentoString
method, we find that theHashMap
did not find the rewrittentoString
method, so let's just go ahead and search for his parent class
Search process, if you use Ctrl + f to search the entire class, you will see a toString query record, here for the HashMap's internal class Node's method, not the HashMap's
discoveriesAbstractMap
The class really does override thetoString
methodologies
Here we finally see the iterator, and we return to theHashMap
The class went to look at it.entrySet
What did the method do?
Because we walked through the put method, at this point theHashMap
hit the nail on the headentrySet
is content, you can see here that it is a direct translation of theentrySet
It's back.
entrySet
is actually a Set collection that will be ourHashMap
The storage unit Entry is placed inside the ( )
We then find the location that implements the iterator method in the collection interface via a generic, anotherHashMap
The inner class of theEntrySet
Finding yet another class we haven't seen before, we click on it in passing
click onnextNode
method and found that, hey, this is not the place to report errors, to the point that now wemodCount
There too, the node that reported the error has been found, one more to go.expectedModCount
I didn't find it, so after a quick check, it occurred to me that it could be in one of the constructor methods, and I went back to look at theEntryIterator
I didn't write my own constructor, so I opened his parent class, and it was clear, just look at the picture.
Here, these two buddies finally found all, so here comes the problem again, to theexpectedModCount
The endowment ismodCount
It's worth it. How can these two guys be different?
The answer also surfaced, single-threaded is certainly not a problem, but we are a multi-threaded operation, ah, if the A thread has just finished giving the value, the B thread runningputVal
Way to go, run throughmodCount
+1 now, and then Thread A goes immediately afterward tonextNode
method, a comparison is wrong, and then an exception is thrown
so to speakHashMap
It's still very problematic in concurrent scenarios
ConcurrentHashMap
HashMap
In the multi-threaded scenarios can not be used, not safe ah, so adapted to multi-threaded thread-safe HashMap:ConcurrentHashMap
arise at an opportune time
Then we take the original code'sHashMap
exchange (sth) for (sth else)ConcurrentHashMap
public static void main(String[] args) {
ConcurrentHashMap<String,String> map = new ConcurrentHashMap<>();
for (int i = 0;i < 20; i++){
new Thread(()-> {
(().getName(),new Date().toString());
(map);
},(i)).start();
}
}
Executed N times, indeed, no error, each loop can print successfully, so amazing things, let's see why he does not report an error
First, click on this class to go in and take a look at it
It was found that this class also inherits theAbstractMap
class, describing the relationship with theHashMap
is the division of the same ah, and then we went to find the upper two brothers found that the time, disappeared, and then go to find the iterator and next method found that a completely different set, so naturally, not like this error, then how he is dealing with multi-threaded operation scenarios it
ConcurrentHashMap
attributablesynchronized
+ CAS
algorithm to implement the thread-safe
If you go to the source code, you'll see that theConcurrentHashMap
There's a lot in there.+ data type writing, this writing is the use of CAS algorithm to achieve lock-free modification of the value of the operation, this algorithm can greatly reduce the locking process caused by the performance losses
The algorithm is probably to keep going with the value of the variable in memory and the value of the variable expected by the code is the same, if it is the same will be modified successfully, if not the same will refuse to execute the modification, with this way to determine the current thread in the current thread is the most recent value, if not may be overwritten by the results of other threads
Because of the way the algorithm determines this, if a thread changes the value and then changes it back, the algorithm still assumes that it is the latest value that has not been changed
And by looking at the source code, it was found that the operation of theNode
The related object will be used with thesynchronized
Lock the object