1.7版本
组成元素
Segment
static class Segment<K,V> extends ReentrantLock implements Serializable {
private static final long serialVersionUID = 2249069246763182397L;
final float loadFactor;
Segment(float lf) { this.loadFactor = lf; }
}
HashEntry 没1.7的jdk取源码
Segment和HashEntry都是静态内部类。
①、Segment 继承 ReentrantLock(重入锁) 用来充当锁的角色,每个 Segment 对象守护每个散列映射表的若干个桶;
②、HashEntry 用来封装映射表的键-值对;
③、每个桶是由若干个 HashEntry 对象链接起来的链表
加锁是对sagement数组的元素加锁,一次锁一个元素,线程可以操作其他元素。
1.8
使用cas和synchronize,参考了hashmap。
源码
public V put(K key, V value) {
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();
//计算hash值
int hash = spread(key.hashCode());
int binCount = 0;
//1.8是使用cas做更新操作的,需要一直循环操作直到成功
for (Node<K,V>[] tab = table;;) {
Node<K,V> f; int n, i, fh;
//数组为空,进行初始化
if (tab == null || (n = tab.length) == 0)
tab = initTable();
//找到在数组中的位置,如果该位置为空,就尝试使用cas进行添加,(失败就break,进入下一层循环)这句感觉有问题
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
}
//如果正在移动元素就协助扩容
else if ((fh = f.hash) == MOVED)
tab = helpTransfer(tab, f);
else {
//发送碰撞的情况
V oldVal = null;
//锁住
synchronized (f) {
//判断f是否是链表头结点
if (tabAt(tab, i) == f) {
//如果是,fh(节点哈希值)大于等于0
if (fh >= 0) {
//初始化计数器
binCount = 1;
//循环遍历节点
for (Node<K,V> e = f;; ++binCount) {
K ek;
//key值相同,替换值
if (e.hash == hash &&
((ek = e.key) == key ||
(ek != null && key.equals(ek)))) {
oldVal = e.val;
if (!onlyIfAbsent)
e.val = value;
break;
}
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;
}