Double row set face questions

An underlying source code analysis .HashMap


1. Introduction underlying data structure used HashMap


Array: a linked list of each item in the array is, in fact, a combination of arrays and linked lists
singly linked lists: Hash collision occurs when the first array to find the corresponding position, and then 1.8 tail-insertion method (Method 1.7 using the head insert) forming a unidirectional list structure
after jdk1.8 black tree: when the list is greater than the length of each array 8, is converted to a red-black tree

can explain what is Hash collision? What are some of the solutions to
the different key may produce the same Hash value
solutions Hash collision: Law list, and then hashing
HashMap which made use of the list, and then using them in ConcurrentHashMap hashing


2. Why a red-black tree, such as a binary search tree, and why the critical value of 8


Binary search tree in exceptional circumstances also become a linear structure, and the original list have a common problem, a node is too deep, slow lookup performance
using a red-black tree is mainly used to improve query speed, red-black tree is a balanced binary tree insert the new data will be balanced by L, D, discoloration and other operations, to solve the problem of the depth of the node

when the amount of data, using a high red-black tree efficient than a linked list, as a balanced binary tree takes balance resource, preliminary data less when using a linked list, when the data reaches a certain limit, and then using
red-black tree, you can speed up the data query speed, the best performance for the official test 8 ~


3.put and get the underlying source code of the core processes


The core put method:
public V put (key K, V value) {
// Hash value calculated key, and then passes the Hash value to the key value itself and Value putval method which
return putVal (hash (key), key, value, to false, to true);
}

Final V PutVal (int the hash, K Key, V value, Boolean onlyIfAbsent,
Boolean The evict) {
the Node <K, V> [] Tab; the Node <K, V> P; int n-, I;
IF ((tab = table) == null || (n = tab.length) == 0) // determines the current array is empty, if empty first expansion to be
n = (tab = resize () ). length; // after expansion to the expansion of the size of N
IF ((P = Tab [I = (n--. 1) & the hash]) == null) // get the current array location is determined whether data is present, if empty directly inserted, or need to represent the current position is not empty, not empty judgment required
tab [i] = newNode (hash , key, value, null); // if you create a new node is added to the empty position
the else {
the node <K, V> e; K k;
if (p.hash == hash && (( k = p.key) == key || (key! = null && key.equals (k)))) // Key Hash value determined values are the same, if the same it is necessary to cover Value
E = P;
the else iF (the instanceof the TreeNode P) // node determines whether the current array is stored in the tree node
e = ((TreeNode <K, V>) p) .putTreeVal (this, tab, hash, key, value); // add to the tree node
the else {
for (int BinCount = 0;; BinCount ++) {// loop through the list
if ((e = p.next) == null) {// Analyzing worth whether the next element of the current array position is empty, it is empty if the current element is added to the rear
p.next the newNode = (the hash, Key, value, null);
IF (BinCount> = TREEIFY_THRESHOLD -. 1) // -1 for 1st // after addition is determined how many of the current node list, if the node is greater than or equal to 8 converts red-black tree
treeifyBin (tab, hash); // treeifyBin determines whether the current array is empty, or the length is less than 64, if the 64 is empty or less than
19 // first expansion
BREAK;
}
IF (the hash && == e.hash
(! (k = e.key) == key || (key = null && key.equals (k)))) // Key again repeated determination
BREAK;
P = E;
}
}
! IF (E = null ) {// existing Key Mapping for
V = oldValue e.Value;
! IF (onlyIfAbsent oldValue == null ||)
e.Value = value;
afterNodeAccess (E);
return oldValue;
}
}
++ ModCount;
IF (++ size> threshold) // current number of array elements is determined and a threshold value comparison, if the number is greater than the threshold capacity is needed
after the // default, when the first data is added, will be a first expansion; a resize () add data
afterNodeInsertion (evict); // add to all subsequent data expansion and then
return null;
}
expansion: By default, the size of the array 16, the array elements when the load factor exceeds the size * (0.75), if more than 12 elements , resize the call for expansion, expansion of 2 times the original size
and recalculating the position of elements in the array, it is more cost performance, generally try to predict the size of creating a collection, to avoid multiple expansion


get method core logic:
Final the Node <K, V> the getNode (int the hash, Object Key) {
the Node <K, V> [] Tab; the Node <K, V> First, E; int n-; K K;
IF ((Tab = Table)! null && = (n-= tab.length)> 0 &&
(First Tab = [(n--. 1) & the hash])! = null) {// Analyzing arrays and array elements corresponding to the position of the array is empty
if (first.hash Always && // Check the hash == First Node
((K = first.key) == || Key (Key! = null && key.equals (K)))) // get Key transmission over a corresponding position value and comparing the first element, directly back if equal, if not equal to find
return first;
IF (! (E = first.next) = null) {// the next element determines whether the first element is empty, If not empty
if (first instanceof TreeNode) // if not empty is determined whether the current node is a tree node
return ((TreeNode <K, V >) first) .getTreeNode (hash, key); // If a tree node, getTreeNode get directly the node returns
do {
IF (e.hash the hash == &&
((K = e.key) == || Key (Key!= Null && key.equals (k)))) // cycle one comparisons
return e;
} while ((e = e.next) != null);
}
}
return null;
}


Two .ConcurrentHashMap underlying implementation

 

Between 1.ConcurrentHashMap and HashTable

 


ConcurrentHashMap performance than HashTable, are thread-safe operation can be completed,
Hashtable thread safe use of synchronized synchronization method for locking operation, if a thread is currently accessing the collection, other threads can not be accessed, you need to wait
on the contrary ConcurrentHashMap adopt them segmented lock mechanism

 

1. JDK1.7 and JDK1.8 underlying implementation differences

Before JDK1.8 version, using the segment of ConcurrentHashMap lock technology, the data segments by village is rough, every segment Segment arranged a lock (Inherited of ReentrantLock)
underlying employed: Segment + HashEntry
when data is added, according to the key value segment find corresponding data segments, and then matching the data block, using the linked list is stored

1.1JDK1.7 underlying implementation

In JDK1.7 version, of ConcurrentHashMap data structure consists of a plurality of arrays and Segment HashEntry composition, as shown below:

 

Meaning Segment array is a large table is divided into a plurality of small table to perform the lock, which is locked above-mentioned separation techniques, and each is stored in a Segment element array HashEntry + chain, and that the HashMap as data storage structure

 

1.2JDK1.8 underlying implementation

Achieve JDK1.8 has abandoned the concept of Segment, but directly linked list data structure Node array + + to achieve red-black tree, concurrency control and use Synchronized CAS to operate, the whole looks like optimized and thread-safe the HashMap, although you can still see the data structure Segment in JDK1.8, but has simplified the property, only to compatible with older versions


2. ConcurrentHashMap put the underlying core logic implemented method


V PUT public (Key K, V value) {
return PutVal (Key, value, to false);
}



/ ** * Implementation for the putIfAbsent PUT and /
Final V PutVal (Key K, V value, Boolean onlyIfAbsent) {
IF (Key = = null || value == null) throw new NullPointerException (); // key and determines whether the value is null, if blank reported abnormal
int hash = spread (key.hashCode () ); // recalculate the hash key value, effectively reduce the Hash value conflicts
int BinCount = 0;
for (the Node <K, V> [] Tab = Table ;;) {// iterate current array data among all
Node <K, V> f; int n, i , FH;
IF (Tab == null || (= n-tab.length) == 0) // determines whether the array is empty
tab = initTable (); // if empty array initialization operation to be performed
else if (( f = tabAt (tab, i = (n - 1) & hash)) == null) {// find the location of the key according to the Hash value, if the position is not the element
if (casTabAt (tab, i, null,
new Node <K, V> ( hash, key, value, null))) // acquired empty element, and then re-create a new Node put to
BREAK; // NO Lock When Adding to empty bin
}
the else IF ( (fh = f.hash) == MOVED) // determines whether the current state of the expansion element array
Tab = helpTransfer (Tab, F);
the else {
V oldVal = null;
the synchronized (F) {// lock
if (tabAt ( Tab, I) == F) {
IF (FH> = 0) {
BinCount =. 1;
for (the Node <K, V> E = F BinCount ;; ++) {
K EK;
IF (the hash == e.hash // add && determination key and the original key for the key value and the Hash value determination judgment, if the equal coverage
((EK = e.key) == || key
(EK! = null && key.equals (EK)) )) {
oldVal = e.val;
! IF (onlyIfAbsent)
e.val = value;
BREAK;
}
the Node <K, V> Pred = E;
if ((e = e.next) == null) {// determines whether the next current node is empty, empty if it is added to the next node which
pred.next = new Node <K, V > (hash , Key,
value, null);
BREAK;
}
}
}
the else iF (F TreeBin the instanceof) {// determines whether the current node is a red-black tree
the node <K, V> P;
BinCount = 2;
iF ((P = (( TreeBin <K, V>) F) .putTreeVal (the hash, Key,
! value)) = null) {// Create a tree node if the red-black tree
oldVal = p.val;
! IF (onlyIfAbsent)
p.val value =;
}
}
}
}
IF (! BinCount = 0) {
IF (BinCount> = TREEIFY_THRESHOLD) // number of cycles is determined according to the current number of data exists in the list, if the data is greater than a threshold equal to 8
// black tree is performed conversion
treeifyBin (Tab, I);
IF (! oldVal = null)
return oldVal;
BREAK;
}
}
}
AddCount (1L, BinCount); // determine whether to expansion
return null;
}

Guess you like

Origin www.cnblogs.com/ringqq/p/12511906.html