hashmap原理
1.put原理
主要思想就是插入的时候,首先根据key的hash值计算node数组的位置,并判断是否为空,如果为空就直接插入数据。如果不为空,就判断要插入的值是否与第一个数据相同,不相同就继续判断是不是红黑树,是就遍历红黑树,否则继续遍历链表遇到相同的就终止。采用的是尾插,插入之后判断是否达到阈值,容量乘以负载因子0.75,达到之后就扩容。
主体就是数组+链表+红黑树
public V put(K key, V value) {
return this.putVal(hash(key), key, value, false, true);
}
final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) {
HashMap.Node[] tab;
int n;
if ((tab = this.table) == null || (n = tab.length) == 0) {
n = (tab = this.resize()).length;
}
Object p;
int i;
if ((p = tab[i = n - 1 & hash]) == null) {
tab[i] = this.newNode(hash, key, value, (HashMap.Node)null);
} else {
Object e;
Object k;
if (((HashMap.Node)p).hash == hash && ((k = ((HashMap.Node)p).key) == key || key != null && key.equals(k))) {
e = p;
} else if (p instanceof HashMap.TreeNode) {
e = ((HashMap.TreeNode)p).putTreeVal(this, tab, hash, key, value);
} else {
int binCount = 0;
while(true) {
if ((e = ((HashMap.Node)p).next) == null) {
((HashMap.Node)p).next = this.newNode(hash, key, value, (HashMap.Node)null);
if (binCount >= 7) {
this.treeifyBin(tab, hash);
}
break;
}
if (((HashMap.Node)e).hash == hash && ((k = ((HashMap.Node)e).key) == key || key != null && key.equals(k))) {
break;
}
p = e;
++binCount;
}
}
if (e != null) {
V oldValue = ((HashMap.Node)e).value;
if (!onlyIfAbsent || oldValue == null) {
((HashMap.Node)e).value = value;
}
this.afterNodeAccess((HashMap.Node)e);
return oldValue;
}
}
++this.modCount;
if (++this.size > this.threshold) {
this.resize();
}
this.afterNodeInsertion(evict);
return null;
}
2.get原理
主要思想就是插入的时候,首先根据key的hash值计算node数组的位置。首先比较位置上面第一个值是否相等,不相等就判断结构是不是红黑树,是就去查询,否则就遍历链表。
public V get(Object key) {
HashMap.Node e;
return (e = this.getNode(hash(key), key)) == null ? null : e.value;
}
final HashMap.Node<K, V> getNode(int hash, Object key) {
HashMap.Node[] tab;
HashMap.Node first;
int n;
if ((tab = this.table) != null && (n = tab.length) > 0 && (first = tab[n - 1 & hash]) != null) {
Object k;
if (first.hash == hash && ((k = first.key) == key || key != null && key.equals(k))) {
return first;
}
HashMap.Node e;
if ((e = first.next) != null) {
if (first instanceof HashMap.TreeNode) {
return ((HashMap.TreeNode)first).getTreeNode(hash, key);
}
do {
if (e.hash == hash && ((k = e.key) == key || key != null && key.equals(k))) {
return e;
}
} while((e = e.next) != null);
}
}
return null;
}
concurrenthashmap原理
因为多了casTabAt(tab, i, (ConcurrentHashMap.Node)null, new ConcurrentHashMap.Node(hash, key, value)) 和syncroniczed,所以线程安全
1.put原理
final V putVal(K key, V value, boolean onlyIfAbsent) {
if (key != null && value != null) {
int hash = spread(key.hashCode());
int binCount = 0;
ConcurrentHashMap.Node[] tab = this.table;
while(true) {
int n;
while(tab == null || (n = tab.length) == 0) {
tab = this.initTable();
}
ConcurrentHashMap.Node f;
int i;
if ((f = tabAt(tab, i = n - 1 & hash)) == null) {
if (casTabAt(tab, i, (ConcurrentHashMap.Node)null, new ConcurrentHashMap.Node(hash, key, value))) {
break;
}
} else {
int fh;
if ((fh = f.hash) == -1) {
tab = this.helpTransfer(tab, f);
} else {
Object fk;
Object fv;
if (onlyIfAbsent && fh == hash && ((fk = f.key) == key || fk != null && key.equals(fk)) && (fv = f.val) != null) {
return fv;
}
V oldVal = null;
synchronized(f) {
if (tabAt(tab, i) == f) {
if (fh < 0) {
if (f instanceof ConcurrentHashMap.TreeBin) {
binCount = 2;
ConcurrentHashMap.TreeNode p;
if ((p = ((ConcurrentHashMap.TreeBin)f).putTreeVal(hash, key, value)) != null) {
oldVal = p.val;
if (!onlyIfAbsent) {
p.val = value;
}
}
} else if (f instanceof ConcurrentHashMap.ReservationNode) {
throw new IllegalStateException("Recursive update");
}
} else {
label124: {
binCount = 1;
ConcurrentHashMap.Node e;
Object ek;
for(e = f; e.hash != hash || (ek = e.key) != key && (ek == null || !key.equals(ek)); ++binCount) {
ConcurrentHashMap.Node<K, V> pred = e;
if ((e = e.next) == null) {
pred.next = new ConcurrentHashMap.Node(hash, key, value);
break label124;
}
}
oldVal = e.val;
if (!onlyIfAbsent) {
e.val = value;
}
}
}
}
}
if (binCount != 0) {
if (binCount >= 8) {
this.treeifyBin(tab, i);
}
if (oldVal != null) {
return oldVal;
}
break;
}
}
}
}
this.addCount(1L, binCount);
return null;
} else {
throw new NullPointerException();
}
}
2.get原理
public V get(Object key) {
int h = spread(key.hashCode());
ConcurrentHashMap.Node[] tab;
ConcurrentHashMap.Node e;
int n;
if ((tab = this.table) != null && (n = tab.length) > 0 && (e = tabAt(tab, n - 1 & h)) != null) {
int eh;
Object ek;
if ((eh = e.hash) == h) {
if ((ek = e.key) == key || ek != null && key.equals(ek)) {
return e.val;
}
} else if (eh < 0) {
ConcurrentHashMap.Node p;
return (p = e.find(h, key)) != null ? p.val : null;
}
while((e = e.next) != null) {
if (e.hash == h && ((ek = e.key) == key || ek != null && key.equals(ek))) {
return e.val;
}
}
}
return null;
}
总结
hashmap的原理 如上源码。
hash冲突的解决方式1.开放寻址法 2.链地址法 hashmap采用后一种