业务逻辑
- 1,校验参数
- 2,根据key获取hash值
- 3,循环table数组
- 3.1,如果table数组为空,则进行初始化
- 3.2,如果table的i下标是空的,则创建对象放入当前下标下
- 3.3,如果table正在初始化,或者扩容,则进行帮助扩容
- 3.4,添加对象到链表尾部
- 3.4.1,对数据进行加锁
- 3.4.2,循环查找与当前key一致的对象
- 3.4.2.1,如果和当前key的一致的对象存在,则根据onlyIfAbsent的要求,选择是否替换旧值
- 3.4.2.2,如果没有,则把创建对象,并打当前对象放到链表的尾部
- 3.4.3,判断当前链表是否需要树化(链表长度超过8,则进行树化)
源码分析
put
/**
* Maps the specified key to the specified value in this table.
* Neither the key nor the value can be null.
*
* <p>The value can be retrieved by calling the {@code get} method
* with a key that is equal to the original key.
*
* @param key key with which the specified value is to be associated
* @param value value to be associated with the specified key
* @return the previous value associated with {@code key}, or
* {@code null} if there was no mapping for {@code key}
* @throws NullPointerException if the specified key or value is null
*/
public V put(K key, V value) {
//看putVal
return putVal(key, value, false);
}
putVal
/** Implementation for put and putIfAbsent */
final V putVal(K key, V value, boolean onlyIfAbsent) {
//校验参数
if (key == null || value == null) throw new NullPointerException();
//获取key的hash值
int hash = spread(key.hashCode());
int binCount = 0;
//循环table数组
for (Node<K,V>[] tab = table;;) {
Node<K,V> f; int n, i, fh;
//如果table数组是空的,则进行初始化,原子操作
if (tab == null || (n = tab.length) == 0)
tab = initTable();
//根据hash计算出下标,并取值改制,原子操作
else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
//添加对象
if (casTabAt(tab, i, null,
new Node<K,V>(hash, key, value, null)))
break; // no lock when adding to empty bin
}
//如果table在扩容,则帮助其扩容
else if ((fh = f.hash) == MOVED)
tab = helpTransfer(tab, f);
else {
V oldVal = null;
//加锁
synchronized (f) {
if (tabAt(tab, i) == f) {
if (fh >= 0) {
binCount = 1;
for (Node<K,V> e = f;; ++binCount) {
K ek;
//如果key冲突,则覆盖原有value
if (e.hash == hash &&
((ek = e.key) == key ||
(ek != null && key.equals(ek)))) {
oldVal = e.val;
//是否替换旧值
if (!onlyIfAbsent)
e.val = value;
break;
}
//如果没有冲突的key,则把新的对象加入链表(绑定链表尾端)
Node<K,V> pred = e;
if ((e = e.next) == null) {
pred.next = new Node<K,V>(hash, key,
value, null);
break;
}
}
}
//如果是树结构,则加入树中
else if (f instanceof TreeBin) {
Node<K,V> p;
binCount = 2;
//加入树中
if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key,
value)) != null) {
oldVal = p.val;
//是否替换旧值
if (!onlyIfAbsent)
p.val = value;
}
}
}
}
//是否需要转化为树结构
if (binCount != 0) {
if (binCount >= TREEIFY_THRESHOLD)
//转化为树结构
treeifyBin(tab, i);
if (oldVal != null)
return oldVal;
break;
}
}
}
addCount(1L, binCount);
return null;
}
spread
static final int HASH_BITS = 0x7fffffff; // usable bits of normal node hash
/**
* Spreads (XORs) higher bits of hash to lower and also forces top
* bit to 0. Because the table uses power-of-two masking, sets of
* hashes that vary only in bits above the current mask will
* always collide. (Among known examples are sets of Float keys
* holding consecutive whole numbers in small tables.) So we
* apply a transform that spreads the impact of higher bits
* downward. There is a tradeoff between speed, utility, and
* quality of bit-spreading. Because many common sets of hashes
* are already reasonably distributed (so don't benefit from
* spreading), and because we use trees to handle large sets of
* collisions in bins, we just XOR some shifted bits in the
* cheapest possible way to reduce systematic lossage, as well as
* to incorporate impact of the highest bits that would otherwise
* never be used in index calculations because of table bounds.
*/
static final int spread(int h) {
//key的hash值右移16位,并与hash值进行^计算,在与HASH_BITS 进行&计算
return (h ^ (h >>> 16)) & HASH_BITS;
}