原理:cas + synchronized + 数组 + 链表 + 红黑树
public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
implements ConcurrentMap<K,V>, Serializable {
// hash表的最大容量
private static final int MAXIMUM_CAPACITY = 1 << 30;
// hash表的初始容量
private static final int DEFAULT_CAPACITY = 16;
// 最大数组长度,可能在toArray()相关方法中用到
static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
// 默认并发级别 jdk1.7 之前遗留的 1.8只用于初始化,没有使用,后续版本会移除掉
private static final int DEFAULT_CONCURRENCY_LEVEL = 16;
// 负载因子
private static final float LOAD_FACTOR = 0.75f;
// 链表树化条件,即hash表冲突链表的元素 > 8,会作为链表转红黑树的一个条件
static final int TREEIFY_THRESHOLD = 8;
// 取消树化条件
static final int UNTREEIFY_THRESHOLD = 6;
// hash表树化的最小节点容量,即只有hash表的长度 > 64 && 链表长度 > 8 才会将链表转为红黑树,否则只是resize扩容hash表
static final int MIN_TREEIFY_CAPACITY = 64;
// 线程迁移数据最小步长 控制线程迁移任务最小区间的一个值
private static final int MIN_TRANSFER_STRIDE = 16;
// 扩容用 计算扩容生成一个标识戳
private static int = 16;
// 65535 标识并发扩容最大线程数量
private static final int MAX_RESIZERS = (1 << (32 - RESIZE_STAMP_BITS)) - 1;
// 扩容相关
private static final int RESIZE_STAMP_SHIFT = 32 - RESIZE_STAMP_BITS;
// node 结点的hash 是-1 表示 当前结点是forwardingNode结点
/**
ForwardingNode是一种临时节点,在扩容进行中才会出现,并且它不存储实际的数据。
如果旧数组的一个hash桶中全部的节点都迁移到新数组中,旧数组就在这个hash桶中放置一个ForwardingNode.
读操作或者迭代读时碰到ForwardingNode时,将操作转发到扩容后的新的table数组上去执行,写操作碰见它时,则尝试帮助扩容。
*/
static final int MOVED = -1; // hash for forwarding nodes
// 红黑树的代理结点
/**
TreeBin是ConcurrentHashMap中用于代理操作TreeNode的特殊节点,持有存储实际数据的红黑树的根节点。
因为红黑树进行写入操作,整个树的结构可能会有很大的变化,这个对读线程有很大的影响,所以TreeBin还要维护一个简单读写锁,
这是相对HashMap,这个类新引入这种特殊节点的重要原因。
*/
static final int TREEBIN = -2; // hash for roots of trees
// 代表当前节点是一个保留节点,即占位符
static final int RESERVED = -3; // hash for transient reservations
// 0x7fffffff = 31个1 用于将一个负数变成一个正数 但是不是取绝对值
static final int HASH_BITS = 0x7fffffff; // usable bits of normal node hash
// 系统cpu数量
static final int NCPU = Runtime.getRuntime().availableProcessors();
// 用于序列化兼容
private static final ObjectStreamField[] serialPersistentFields = {
new ObjectStreamField("segments", Segment[].class),
new ObjectStreamField("segmentMask", Integer.TYPE),
new ObjectStreamField("segmentShift", Integer.TYPE)
};
// hash表
transient volatile Node<K,V>[] table;
// 扩容时用的hash表
private transient volatile Node<K,V>[] nextTable;
// baseCount属性是在没有争用现象时的基本计数器值,也在初始化表的竞争中使用。
private transient volatile long baseCount;
/**
sizeCtl < 0
1. -1 的时候 表示table正在初始化(有线程正在初始化, 当前线程应该自旋等待)
2. 其他情况 表示当前map正在进行扩容 高16位表示 扩容的标识戳, 低16位表示 扩容线程数量
sizeCtl = 0
表示创建数组 使用默认容量 16 表示没有初始化
sizeCtl > 0
1. 如果table 未初始化 表示 初始化大小 putAll方法
2. 如果table 已经初始化 表示下次扩容的阈值
*/
private transient volatile int sizeCtl;
//扩容过程中,记录当前进度,所有线程都需要从transferIndex中分配区间任务,去执行自己的任务
private transient volatile int transferIndex;
// 0:表示无锁 1:表示加锁
private transient volatile int cellsBusy;
// LongAdder 中的cells 数组 当baseCount发生竞争后 会创建cells 数组
// 线程会通过计算hash值 取到自己的cell中
private transient volatile CounterCell[] counterCells;
// views
private transient KeySetView<K,V> keySet;
private transient ValuesView<K,V> values;
private transient EntrySetView<K,V> entrySet;
}
static class Node<K,V> implements Map.Entry<K,V> {
final int hash; //节点hash值
final K key; // key
volatile V val; // value
volatile Node<K,V> next; // 下一个节点的值
Node(int hash, K key, V val, Node<K,V> next) {
this.hash = hash;
this.key = key;
this.val = val;
this.next = next;
}
public final K getKey() { return key; }
public final V getValue() { return val; }
public final int hashCode() { return key.hashCode() ^ val.hashCode(); }
public final String toString(){ return key + "=" + val; }
public final V setValue(V value) {
throw new UnsupportedOperationException();
}
public final boolean equals(Object o) {
Object k, v, u; Map.Entry<?,?> e;
return ((o instanceof Map.Entry) &&
(k = (e = (Map.Entry<?,?>)o).getKey()) != null &&
(v = e.getValue()) != null &&
(k == key || k.equals(key)) &&
(v == (u = val) || v.equals(u)));
}
// 支持get方法,在子类中被覆盖使用
Node<K,V> find(int h, Object k) {
Node<K,V> e = this;
if (k != null) {
do {
K ek;
if (e.hash == h &&
((ek = e.key) == k || (ek != null && k.equals(ek))))
return e;
} while ((e = e.next) != null);
}
return null;
}
}
用来标识旧hash表扩容后占位的临时节点,即当前桶扩容迁移成功的标识
static final class ForwardingNode<K,V> extends Node<K,V> {
final Node<K,V>[] nextTable; // 扩容引用,即新的hash表
ForwardingNode(Node<K,V>[] tab) {
super(MOVED, null, null, null);
this.nextTable = tab;
}
Node<K,V> find(int h, Object k) {
// 自旋
// outer:最外层的循环标签
/*
* tab一定不为null
* 整个ConcurrentHashMap源码中,只有一个地方实例化ForwardingNode,
* 就是在transfer迁移数据方法中执行了:ForwardingNode fwd = new ForwardingNode(nextTab);
* 将新表赋值给tab
*/
outer: for (Node<K,V>[] tab = nextTable;;) {
/*
* e 表示新表中寻址算法得到的桶位头结点
* n 表示新表的长度
*/
Node<K,V> e; int n;
/*
* 条件1 2 3 永远不成立
* 条件4:在新扩容表中 重新定位 hash 对应的头结点
* true -> 1.在oldTable中 对应的桶位在迁移之前就是null
* 2.扩容完成后,有其它写线程,将此桶位设置为了null
*/
if (k == null || tab == null || (n = tab.length) == 0 ||
(e = tabAt(tab, (n - 1) & h)) == null)
return null; // 新表桶位没有数据 直接返回null
/*
* 前置条件:扩容后的表,对应hash的桶位不是null,e为此桶位的头结点
* e可能是哪些类型?
* 1.node类型
* 2.TreeBin类型
* 3.FWD类型(高并发下扩容后再次触发扩容)
*/
// 自旋
for (;;) {
/*
* eh:新扩容后表指定桶位的当前节点的hash
* ek:新扩容后表指定桶位的当前节点的key
*/
int eh; K ek;
// 当前桶位查找成功
if ((eh = e.hash) == h &&
((ek = e.key) == k || (ek != null && k.equals(ek))))
return e;
/*
* eh < 0
* 1.可能是TreeBin节点
* 2.可能是FWD节点(新扩容后的表,可能在并发很大的情况下,再次扩容)
*/
if (eh < 0) {
// fwd节点 继续进行外层循环,继续在新表中查找
if (e instanceof ForwardingNode) {
// 在新的fwd节点中拿到更新的表
tab = ((ForwardingNode<K,V>)e).nextTable;
continue outer; // 从最外层循环开始执行
}
// 说明此桶位为TreeBin节点,使用TreeBin.find()查找红黑树中相应节点
else
return e.find(h, k);
}
// 此处桶位是链表,遍历到链表末尾也没有找到目标节点,返回null
if ((e = e.next) == null)
return null;
}
}
}
}
}
//tabAt()方法可以获得在 i 位置上的 Node 节点。
static final <K,V> Node<K,V> tabAt(Node<K,V>[] tab, int i) {
return (Node<K,V>)U.getObjectVolatile(tab, ((long)i << ASHIFT) + ABASE);
}
static final class TreeNode<K,V> extends Node<K,V> {
TreeNode<K,V> parent; // red-black tree links
TreeNode<K,V> left;
TreeNode<K,V> right;
TreeNode<K,V> prev; // needed to unlink next upon deletion
boolean red;
TreeNode(int hash, K key, V val, Node<K,V> next,
TreeNode<K,V> parent) {
super(hash, key, val, next);
this.parent = parent;
}
Node<K,V> find(int h, Object k) {
return findTreeNode(h, k, null);
}
/**
* Returns the TreeNode (or null if not found) for the given key
* starting at given root.
*/
final TreeNode<K,V> findTreeNode(int h, Object k, Class<?> kc) {
if (k != null) {
TreeNode<K,V> p = this;
do {
int ph, dir; K pk; TreeNode<K,V> q;
TreeNode<K,V> pl = p.left, pr = p.right;
if ((ph = p.hash) > h)
p = pl;
else if (ph < h)
p = pr;
else if ((pk = p.key) == k || (pk != null && k.equals(pk)))
return p;
else if (pl == null)
p = pr;
else if (pr == null)
p = pl;
else if ((kc != null ||
(kc = comparableClassFor(k)) != null) &&
(dir = compareComparables(kc, k, pk)) != 0)
p = (dir < 0) ? pl : pr;
else if ((q = pr.findTreeNode(h, k, kc)) != null)
return q;
else
p = pl;
} while (p != null);
}
return null;
}
}
static final class TreeBin<K,V> extends Node<K,V> {
TreeNode<K,V> root;
volatile TreeNode<K,V> first;
volatile Thread waiter;
volatile int lockState;
// values for lockState
static final int WRITER = 1; // set while holding write lock
static final int WAITER = 2; // set when waiting for write lock
static final int READER = 4; // increment value for setting read lock
/**
* Tie-breaking utility for ordering insertions when equal
* hashCodes and non-comparable. We don't require a total
* order, just a consistent insertion rule to maintain
* equivalence across rebalancings. Tie-breaking further than
* necessary simplifies testing a bit.
*/
static int tieBreakOrder(Object a, Object b) {
int d;
if (a == null || b == null ||
(d = a.getClass().getName().
compareTo(b.getClass().getName())) == 0)
d = (System.identityHashCode(a) <= System.identityHashCode(b) ?
-1 : 1);
return d;
}
/**
* Creates bin with initial set of nodes headed by b.
*/
TreeBin(TreeNode<K,V> b) {
super(TREEBIN, null, null, null);
this.first = b;
TreeNode<K,V> r = null;
for (TreeNode<K,V> x = b, next; x != null; x = next) {
next = (TreeNode<K,V>)x.next;
x.left = x.right = null;
if (r == null) {
x.parent = null;
x.red = false;
r = x;
}
else {
K k = x.key;
int h = x.hash;
Class<?> kc = null;
for (TreeNode<K,V> p = r;;) {
int dir, ph;
K pk = p.key;
if ((ph = p.hash) > h)
dir = -1;
else if (ph < h)
dir = 1;
else if ((kc == null &&
(kc = comparableClassFor(k)) == null) ||
(dir = compareComparables(kc, k, pk)) == 0)
dir = tieBreakOrder(k, pk);
TreeNode<K,V> xp = p;
if ((p = (dir <= 0) ? p.left : p.right) == null) {
x.parent = xp;
if (dir <= 0)
xp.left = x;
else
xp.right = x;
r = balanceInsertion(r, x);
break;
}
}
}
}
this.root = r;
assert checkInvariants(root);
}
/**
* Acquires write lock for tree restructuring.
*/
private final void lockRoot() {
if (!U.compareAndSwapInt(this, LOCKSTATE, 0, WRITER))
contendedLock(); // offload to separate method
}
/**
* Releases write lock for tree restructuring.
*/
private final void unlockRoot() {
lockState = 0;
}
/**
* Possibly blocks awaiting root lock.
*/
private final void contendedLock() {
boolean waiting = false;
for (int s;;) {
if (((s = lockState) & ~WAITER) == 0) {
if (U.compareAndSwapInt(this, LOCKSTATE, s, WRITER)) {
if (waiting)
waiter = null;
return;
}
}
else if ((s & WAITER) == 0) {
if (U.compareAndSwapInt(this, LOCKSTATE, s, s | WAITER)) {
waiting = true;
waiter = Thread.currentThread();
}
}
else if (waiting)
LockSupport.park(this);
}
}
/**
* Returns matching node or null if none. Tries to search
* using tree comparisons from root, but continues linear
* search when lock not available.
*/
final Node<K,V> find(int h, Object k) {
if (k != null) {
for (Node<K,V> e = first; e != null; ) {
int s; K ek;
if (((s = lockState) & (WAITER|WRITER)) != 0) {
if (e.hash == h &&
((ek = e.key) == k || (ek != null && k.equals(ek))))
return e;
e = e.next;
}
else if (U.compareAndSwapInt(this, LOCKSTATE, s,
s + READER)) {
TreeNode<K,V> r, p;
try {
p = ((r = root) == null ? null :
r.findTreeNode(h, k, null));
} finally {
Thread w;
if (U.getAndAddInt(this, LOCKSTATE, -READER) ==
(READER|WAITER) && (w = waiter) != null)
LockSupport.unpark(w);
}
return p;
}
}
}
return null;
}
/**
* Finds or adds a node.
* @return null if added
*/
final TreeNode<K,V> putTreeVal(int h, K k, V v) {
Class<?> kc = null;
boolean searched = false;
for (TreeNode<K,V> p = root;;) {
int dir, ph; K pk;
if (p == null) {
first = root = new TreeNode<K,V>(h, k, v, null, null);
break;
}
else if ((ph = p.hash) > h)
dir = -1;
else if (ph < h)
dir = 1;
else if ((pk = p.key) == k || (pk != null && k.equals(pk)))
return p;
else if ((kc == null &&
(kc = comparableClassFor(k)) == null) ||
(dir = compareComparables(kc, k, pk)) == 0) {
if (!searched) {
TreeNode<K,V> q, ch;
searched = true;
if (((ch = p.left) != null &&
(q = ch.findTreeNode(h, k, kc)) != null) ||
((ch = p.right) != null &&
(q = ch.findTreeNode(h, k, kc)) != null))
return q;
}
dir = tieBreakOrder(k, pk);
}
TreeNode<K,V> xp = p;
if ((p = (dir <= 0) ? p.left : p.right) == null) {
TreeNode<K,V> x, f = first;
first = x = new TreeNode<K,V>(h, k, v, f, xp);
if (f != null)
f.prev = x;
if (dir <= 0)
xp.left = x;
else
xp.right = x;
if (!xp.red)
x.red = true;
else {
lockRoot();
try {
root = balanceInsertion(root, x);
} finally {
unlockRoot();
}
}
break;
}
}
assert checkInvariants(root);
return null;
}
/**
* Removes the given node, that must be present before this
* call. This is messier than typical red-black deletion code
* because we cannot swap the contents of an interior node
* with a leaf successor that is pinned by "next" pointers
* that are accessible independently of lock. So instead we
* swap the tree linkages.
*
* @return true if now too small, so should be untreeified
*/
final boolean removeTreeNode(TreeNode<K,V> p) {
TreeNode<K,V> next = (TreeNode<K,V>)p.next;
TreeNode<K,V> pred = p.prev; // unlink traversal pointers
TreeNode<K,V> r, rl;
if (pred == null)
first = next;
else
pred.next = next;
if (next != null)
next.prev = pred;
if (first == null) {
root = null;
return true;
}
if ((r = root) == null || r.right == null || // too small
(rl = r.left) == null || rl.left == null)
return true;
lockRoot();
try {
TreeNode<K,V> replacement;
TreeNode<K,V> pl = p.left;
TreeNode<K,V> pr = p.right;
if (pl != null && pr != null) {
TreeNode<K,V> s = pr, sl;
while ((sl = s.left) != null) // find successor
s = sl;
boolean c = s.red; s.red = p.red; p.red = c; // swap colors
TreeNode<K,V> sr = s.right;
TreeNode<K,V> pp = p.parent;
if (s == pr) { // p was s's direct parent
p.parent = s;
s.right = p;
}
else {
TreeNode<K,V> sp = s.parent;
if ((p.parent = sp) != null) {
if (s == sp.left)
sp.left = p;
else
sp.right = p;
}
if ((s.right = pr) != null)
pr.parent = s;
}
p.left = null;
if ((p.right = sr) != null)
sr.parent = p;
if ((s.left = pl) != null)
pl.parent = s;
if ((s.parent = pp) == null)
r = s;
else if (p == pp.left)
pp.left = s;
else
pp.right = s;
if (sr != null)
replacement = sr;
else
replacement = p;
}
else if (pl != null)
replacement = pl;
else if (pr != null)
replacement = pr;
else
replacement = p;
if (replacement != p) {
TreeNode<K,V> pp = replacement.parent = p.parent;
if (pp == null)
r = replacement;
else if (p == pp.left)
pp.left = replacement;
else
pp.right = replacement;
p.left = p.right = p.parent = null;
}
root = (p.red) ? r : balanceDeletion(r, replacement);
if (p == replacement) { // detach pointers
TreeNode<K,V> pp;
if ((pp = p.parent) != null) {
if (p == pp.left)
pp.left = null;
else if (p == pp.right)
pp.right = null;
p.parent = null;
}
}
} finally {
unlockRoot();
}
assert checkInvariants(root);
return false;
}
/* ------------------------------------------------------------ */
// Red-black tree methods, all adapted from CLR
static <K,V> TreeNode<K,V> rotateLeft(TreeNode<K,V> root,
TreeNode<K,V> p) {
TreeNode<K,V> r, pp, rl;
if (p != null && (r = p.right) != null) {
if ((rl = p.right = r.left) != null)
rl.parent = p;
if ((pp = r.parent = p.parent) == null)
(root = r).red = false;
else if (pp.left == p)
pp.left = r;
else
pp.right = r;
r.left = p;
p.parent = r;
}
return root;
}
static <K,V> TreeNode<K,V> rotateRight(TreeNode<K,V> root,
TreeNode<K,V> p) {
TreeNode<K,V> l, pp, lr;
if (p != null && (l = p.left) != null) {
if ((lr = p.left = l.right) != null)
lr.parent = p;
if ((pp = l.parent = p.parent) == null)
(root = l).red = false;
else if (pp.right == p)
pp.right = l;
else
pp.left = l;
l.right = p;
p.parent = l;
}
return root;
}
static <K,V> TreeNode<K,V> balanceInsertion(TreeNode<K,V> root,
TreeNode<K,V> x) {
x.red = true;
for (TreeNode<K,V> xp, xpp, xppl, xppr;;) {
if ((xp = x.parent) == null) {
x.red = false;
return x;
}
else if (!xp.red || (xpp = xp.parent) == null)
return root;
if (xp == (xppl = xpp.left)) {
if ((xppr = xpp.right) != null && xppr.red) {
xppr.red = false;
xp.red = false;
xpp.red = true;
x = xpp;
}
else {
if (x == xp.right) {
root = rotateLeft(root, x = xp);
xpp = (xp = x.parent) == null ? null : xp.parent;
}
if (xp != null) {
xp.red = false;
if (xpp != null) {
xpp.red = true;
root = rotateRight(root, xpp);
}
}
}
}
else {
if (xppl != null && xppl.red) {
xppl.red = false;
xp.red = false;
xpp.red = true;
x = xpp;
}
else {
if (x == xp.left) {
root = rotateRight(root, x = xp);
xpp = (xp = x.parent) == null ? null : xp.parent;
}
if (xp != null) {
xp.red = false;
if (xpp != null) {
xpp.red = true;
root = rotateLeft(root, xpp);
}
}
}
}
}
}
static <K,V> TreeNode<K,V> balanceDeletion(TreeNode<K,V> root,
TreeNode<K,V> x) {
for (TreeNode<K,V> xp, xpl, xpr;;) {
if (x == null || x == root)
return root;
else if ((xp = x.parent) == null) {
x.red = false;
return x;
}
else if (x.red) {
x.red = false;
return root;
}
else if ((xpl = xp.left) == x) {
if ((xpr = xp.right) != null && xpr.red) {
xpr.red = false;
xp.red = true;
root = rotateLeft(root, xp);
xpr = (xp = x.parent) == null ? null : xp.right;
}
if (xpr == null)
x = xp;
else {
TreeNode<K,V> sl = xpr.left, sr = xpr.right;
if ((sr == null || !sr.red) &&
(sl == null || !sl.red)) {
xpr.red = true;
x = xp;
}
else {
if (sr == null || !sr.red) {
if (sl != null)
sl.red = false;
xpr.red = true;
root = rotateRight(root, xpr);
xpr = (xp = x.parent) == null ?
null : xp.right;
}
if (xpr != null) {
xpr.red = (xp == null) ? false : xp.red;
if ((sr = xpr.right) != null)
sr.red = false;
}
if (xp != null) {
xp.red = false;
root = rotateLeft(root, xp);
}
x = root;
}
}
}
else { // symmetric
if (xpl != null && xpl.red) {
xpl.red = false;
xp.red = true;
root = rotateRight(root, xp);
xpl = (xp = x.parent) == null ? null : xp.left;
}
if (xpl == null)
x = xp;
else {
TreeNode<K,V> sl = xpl.left, sr = xpl.right;
if ((sl == null || !sl.red) &&
(sr == null || !sr.red)) {
xpl.red = true;
x = xp;
}
else {
if (sl == null || !sl.red) {
if (sr != null)
sr.red = false;
xpl.red = true;
root = rotateLeft(root, xpl);
xpl = (xp = x.parent) == null ?
null : xp.left;
}
if (xpl != null) {
xpl.red = (xp == null) ? false : xp.red;
if ((sl = xpl.left) != null)
sl.red = false;
}
if (xp != null) {
xp.red = false;
root = rotateRight(root, xp);
}
x = root;
}
}
}
}
}
/**
* Recursive invariant check
*/
static <K,V> boolean checkInvariants(TreeNode<K,V> t) {
TreeNode<K,V> tp = t.parent, tl = t.left, tr = t.right,
tb = t.prev, tn = (TreeNode<K,V>)t.next;
if (tb != null && tb.next != t)
return false;
if (tn != null && tn.prev != t)
return false;
if (tp != null && t != tp.left && t != tp.right)
return false;
if (tl != null && (tl.parent != t || tl.hash > t.hash))
return false;
if (tr != null && (tr.parent != t || tr.hash < t.hash))
return false;
if (t.red && tl != null && tl.red && tr != null && tr.red)
return false;
if (tl != null && !checkInvariants(tl))
return false;
if (tr != null && !checkInvariants(tr))
return false;
return true;
}
private static final sun.misc.Unsafe U;
private static final long LOCKSTATE;
static {
try {
U = sun.misc.Unsafe.getUnsafe();
Class<?> k = TreeBin.class;
LOCKSTATE = U.objectFieldOffset
(k.getDeclaredField("lockState"));
} catch (Exception e) {
throw new Error(e);
}
}
}
// 添加元素
public V put(K key, V value) {
return putVal(key, value, false);
}
// onlyIfAbsent --> ture:表示如果遇到相同的key 进行不进行置换 false:表示替换
final V putVal(K key, V value, boolean onlyIfAbsent) {
// key && value 都不能是null
if (key == null || value == null) throw new NullPointerException();
// 通过扰动函数 计算出新的hash 高16位也参与运算
int hash = spread(key.hashCode());
// binCount:表示当前k-v 封装成node 后插入到指定桶位后 在桶位中所属链表的下标位置
int binCount = 0;
for (Node<K,V>[] tab = table;;) {// 自旋过程
/*
f ->头结点 n->代表table的长度 i->索引
fh->头结点hash fk->头结点的key fv->头结点的value
*/
Node<K,V> f; int n, i, fh; K fk; V fv;
// hash表没有创建,则进行初始化
if (tab == null || (n = tab.length) == 0){
tab = initTable();
// tabAt(tab,i =(n-1)&hash) 得到头结点
// 判断头结点是不是为空 前置条件 表已经创建
}else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
// cas成功 如果头结点是空 直接用cas 的操作 尝试用new的结点替换 头结点
// cas失败 说明其他线程已经插入了 需要自旋 继续操作
if (casTabAt(tab, i, null, new Node<K,V>(hash, key, value)))
break;
}
// 前置条件 表已经创建 && 头结点不是空
// 判断头结点的hash 是不是等于-1 看是不是forwardingNode结点 如果是 说明哈希表正在处于扩容的情况,则帮助扩容
else if ((fh = f.hash) == MOVED){
// 当前线程帮忙扩容
tab = helpTransfer(tab, f);
// 前置条件 表已经创建 && 头结点不是空 && 不处于扩容中
// 头结点是key相同的结点 并且不支持替换 就直接返回当前结点的值
}else if (onlyIfAbsent
&& fh == hash
&& ((fk = f.key) == key || (fk != null && key.equals(fk)))
&& (fv = f.val) != null){
return fv;
// 前置条件 表已经创建 && 头结点不是空 && 不处于扩容中 && 头结点不是key相同的结点
}else {
// 用于记录旧的value
V oldVal = null;
// 锁住头结点
synchronized (f) {
// 再次查询头结点是不是等于f
// 防止你加锁的过程中 别人已经修改了头结点的值,导致操作出现问题
if (tabAt(tab, i) == f) {
// 前置条件 头结点没有改变
// 判断头结点 是不是普通链表 fh>0
if (fh >= 0) {
// 当前列表的末尾,bincount表示链表的长度
//2 : 当前插入的key 与链表的某个元素key 一样 当前插入操作表示冲突位置 (binCount-1)
binCount = 1;
// 遍历链表
for (Node<K,V> e = f;; ++binCount) {
K ek; // 迭代遍历结点的key
if (e.hash == hash && // 找到了key相同的结点
((ek = e.key) == key ||
(ek != null && key.equals(ek)))) {
oldVal = e.val;// 保留老的值
if (!onlyIfAbsent)
e.val = value;// 更新value
break;
}
// 记录用pred记录上一个结点
Node<K,V> pred = e;
// 判断next 是不是为空
if ((e = e.next) == null) {
// 没有key相同的结点 就 插入在末尾
pred.next = new Node<K,V>(hash, key, value);
break;
}
}
}
// fh<0 说明是Treebin
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;
}
}
else if (f instanceof ReservationNode)
throw new IllegalStateException("Recursive update");
}
}
// 当前桶位不是 null 是红黑树 或者 链表
if (binCount != 0) {
// 是不是需要树化
if (binCount >= TREEIFY_THRESHOLD)
treeifyBin(tab, i);
if (oldVal != null) // key 有没有相同的 发生冲突的情况
return oldVal;
break;
}
}
} //自旋结束
// 统计table 一共有多少数据
// 是不是需要扩容
addCount(1L, binCount);
return null;
}
// 扰动函数,高16位也参与hash运算,目的减少hash冲突
// &HASH_BITS的作用:保证这个数是正数,负数有特殊的含义
static final int spread(int h) {
return (h ^ (h >>> 16)) & HASH_BITS;
}
// 初始化hash表
private final Node<K,V>[] initTable() {
Node<K,V>[] tab; int sc;
while ((tab = table) == null || tab.length == 0) {
// sizeCtrl < 0:表示其他线程正在初始化或者扩容,则让出cpu
if ((sc = sizeCtl) < 0)
Thread.yield(); // lost initialization race; just spin
// 否则使用cas将sizeCtrl设置为-1,表示正在初始化
else if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) {
try {
// 再次判断,防止重复初始化,
// 当一个线程走到sc = n - (n >>> 2);这一步时,其他线程可以走到当前代码块。为了不重复走初始化的逻辑,所以要再次判断
if ((tab = table) == null || tab.length == 0) {
// 获取hash表长度,sizeCtrl > 0则把sizeCtrl作为hash的长度,否则使用默认值16作为初始化长度
int n = (sc > 0) ? sc : DEFAULT_CAPACITY;
// 创建hash表,以n的长度
@SuppressWarnings("unchecked")
Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n];
// 初始化完成table
table = tab = nt;
// 已经初始化完成,则sizeCtrl表示下次扩容时的阈值,所以这里计算的是阈值,比如最开始sc = 16 * 0.75 = 12
sc = n - (n >>> 2);
}
} finally {
// 将sc赋值给sizeCtrl
sizeCtl = sc;
}
break;
}
}
return tab;
}
// cas在hash表的i位置设置值
static final <K,V> boolean casTabAt(Node<K,V>[] tab, int i,
Node<K,V> c, Node<K,V> v) {
return U.compareAndSwapObject(tab, ((long)i << ASHIFT) + ABASE, c, v);
}
// 树化
private final void treeifyBin(Node<K,V>[] tab, int index) {
Node<K,V> b; int n, sc;
if (tab != null) {
// hash表长度 < 64
if ((n = tab.length) < MIN_TREEIFY_CAPACITY)
// 尝试扩容,n左移1位,相当于乘2
tryPresize(n << 1);
// hash表长度 > 64,则转红黑树
else if ((b = tabAt(tab, index)) != null && b.hash >= 0) {
synchronized (b) {
if (tabAt(tab, index) == b) {
TreeNode<K,V> hd = null, tl = null;
// 将Node节点转为TreeNode节点
for (Node<K,V> e = b; e != null; e = e.next) {
TreeNode<K,V> p =
new TreeNode<K,V>(e.hash, e.key, e.val,
null, null);
if ((p.prev = tl) == null)
hd = p;
else
tl.next = p;
tl = p;
}
// new TreeBin构造函数会做转红黑树的操作,然后设置为index位置
setTabAt(tab, index, new TreeBin<K,V>(hd));
}
}
}
}
}
private final void tryPresize(int size) {
// 扩容size如果大于最大值,则取最大值即可,否则tableSizeFor进行向上取2的次方
int c = (size >= (MAXIMUM_CAPACITY >>> 1)) ? MAXIMUM_CAPACITY :
tableSizeFor(size + (size >>> 1) + 1);
int sc;
// 1.没有初始化 2.已经初始化
while ((sc = sizeCtl) >= 0) {
Node<K,V>[] tab = table; int n;
//1.没有初始化,则进行初始化
// 初始化代码片段,同initTable类似, 如果hash表没有初始化,则进行初始化
if (tab == null || (n = tab.length) == 0) {
// n = max(原来的容量sc,扩容的容量c)
n = (sc > c) ? sc : c;
if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) {
try {
if (table == tab) {
@SuppressWarnings("unchecked")
Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n];
table = nt;
sc = n - (n >>> 2);
}
} finally {
sizeCtl = sc;
}
}
}
//2.已经初始化,扩容
// 扩容长度 < 扩容的阈值,说明已经扩容完了,直接退出,不需要管
// 数组长度大于最大值了,无需扩容
else if (c <= sc || n >= MAXIMUM_CAPACITY)
break;
// 开始扩容
else if (tab == table) {
// 得到一个扩容戳(长度为32位,高16位作扩容标识,低16位作扩容线程数)
int rs = resizeStamp(n);
// 表示其他线程正在扩容,帮助扩容
if (sc < 0) {
Node<K,V>[] nt;
// 迁移结束,则break
if ((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 ||
sc == rs + MAX_RESIZERS || (nt = nextTable) == null ||
transferIndex <= 0)
break;
// 当前线程协助扩容
if (U.compareAndSwapInt(this, SIZECTL, sc, sc + 1))
transfer(tab, nt);
}
// 否则当前线程自己扩容
else if (U.compareAndSwapInt(this, SIZECTL, sc,
(rs << RESIZE_STAMP_SHIFT) + 2))
transfer(tab, null);
}
}
}
private final void addCount(long x, int check) {
//cs 是cells 单元
//b 是未发生竞争的base
// s 是元素数量
CounterCell[] cs; long b, s;
// LongAdder 操作
if ((cs = counterCells) != null ||
!U.compareAndSetLong(this, BASECOUNT, b = baseCount, s = b + x)) {
CounterCell c; long v; int m;
boolean uncontended = true;
if (cs == null || (m = cs.length - 1) < 0 ||
(c = cs[ThreadLocalRandom.getProbe() & m]) == null ||
!(uncontended =
U.compareAndSetLong(c, CELLVALUE, v = c.value, v + x))) {
fullAddCount(x, uncontended);
return;
}
if (check <= 1)
return;
//【以线程安全的方式计算concurrentHashMap元素个数】
s = sumCount();
}
// 【检查扩容】
// 如果check >=0 说明一定是put 调用的 addCount
if (check >= 0) {
// tab 表示 map.table
// nt 是nexttable
// n 是数组长度
// sc 是sizeCtl的长度
Node<K,V>[] tab, nt; int n, sc;
// 自旋
// 条件1 s >= (long)(sc = sizeCtl)
// ture 1: 当前sizeCtl 是一个负数 表示正在扩容中。
// 2: 当前sizeCtl 是一个正数 表示扩容阈值
// false 表示当前table 尚未达到扩容条件
// 条件2:(tab = table) != null hash表是否初始化
// 条件3: 当前table长度小于最大值限制 可以扩容
while (s >= (long)(sc = sizeCtl) && (tab = table) != null &&
(n = tab.length) < MAXIMUM_CAPACITY) {
// 获取到唯一标识戳
int rs = resizeStamp(n);
// 条件1
// ture 说明当前线程获取的扩容唯一标识撮 不是本次扩容
// false 说明当前线程获取到的扩容唯一标识撮 是本次扩容
// 条件2
// ture 表示扩容完毕了 false 表示在扩容过程中
// 条件3
// ture : 触发的帮助扩容的达到最大值 65535-1
// false 可以参与
// 条件4
// ture 扩容结束
// false 扩容正在进行
if (sc < 0) {
// 迁移成功则直接break
if ((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 ||
sc == rs + MAX_RESIZERS || (nt = nextTable) == null ||
transferIndex <= 0)
break;
// 当前线程正在扩容中 当前线程参与
// ture 可以参与
//fasle 进行自旋 大概率还会来到这里
//条件失败 1 当前有很多线程都尝试修改sizeCtl 可能会导致和内存的不一样
// transfer 任务内的线程也修改sizeCtl
// 帮助扩容
if (U.compareAndSetInt(this, SIZECTL, sc, sc + 1))
// 协助扩容线程 支持nextTable参数
transfer(tab, nt);
}
// 条件成立 说明当前线程是触发扩容的第一个线程 在transfer方法需要做一些扩容的准备工作
else if (U.compareAndSetInt(this, SIZECTL, sc,
(rs << RESIZE_STAMP_SHIFT) + 2))
//触发扩容的线程 不持有nextTable
transfer(tab, null);
s = sumCount();
}
}
}
final Node<K,V>[] helpTransfer(Node<K,V>[] tab, Node<K,V> f) {
// nextTable 就是fwd.nextTable
Node<K,V>[] nextTab; int sc;
//条件三:
// 恒成立
if (tab != null && (f instanceof ForwardingNode) &&
(nextTab = ((ForwardingNode<K,V>)f).nextTable) != null) {
// 拿当前表的长度 获取扩容标识戳
int rs = resizeStamp(tab.length);
// 条件1 :
// 成立 标识当前扩容正在执行
//不成立 1. nextTable被设置为null 已经扩容完毕了
// 2。 再次出发扩容了 nextTable 已经过期了
//条件2 成立 说明扩容正在进行
// 不成立 扩容结束了 扩容结束之后最后退出的线程会把nextTable设置为table
// 条件3: 扩容正在进行中
// 不成立 sizeCtl 是当前扩容阈值 扩容已经结束了
while (nextTab == nextTable && table == tab &&
(sc = sizeCtl) < 0) {
//当前线程没事干了 直接不进入
if ((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 ||
sc == rs + MAX_RESIZERS || transferIndex <= 0)
break;
// 尝试增加一个线程 帮助扩容
if (U.compareAndSetInt(this, SIZECTL, sc, sc + 1)) {
transfer(tab, nextTab);
break;
}
}
return nextTab;
}
return table;
}
// transfer方法用于将元素从旧的数组迁移到新的数组中
// 参数advance表示是否继续迁移元素
// tab:旧hash表 nextTab:新的hash表,不为null:表示帮助扩容 null:表示自己扩容
private final void transfer(Node<K,V>[] tab, Node<K,V>[] nextTab) {
// n:扩容之前table数组的长度 tride:分配给线程任务的步长,即每个线程迁移的数据范围
int n = tab.length, stride;
// 结合cpu核心数计算每个线程要迁移的数据大小
if ((stride = (NCPU > 1) ? (n >>> 3) / NCPU : n) < MIN_TRANSFER_STRIDE)
stride = MIN_TRANSFER_STRIDE; // 每个线程最小的迁移数量为16
// nextTab为空,说明是第一次扩容,需要创建一个新的hash表
if (nextTab == null) {
try {
// 创建了比扩容之前大1倍的table
@SuppressWarnings("unchecked")
Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n << 1];
nextTab = nt;
} catch (Throwable ex) { // try to cope with OOME
sizeCtl = Integer.MAX_VALUE;
return;
}
nextTable = nextTab; // 方便协助线程 拿到新表
transferIndex = n;// 记录迁移数据整体位置的一个标记 从1开始
}
// 新表长度
int nextn = nextTab.length;
// 新表的引用 当某个桶位处理完毕 将设置为fwd 结点
ForwardingNode<K,V> fwd = new ForwardingNode<K,V>(nextTab);
boolean advance = true;// 推进标记,标识是否继续迁移元素
boolean finishing = false; // 完成标记
// i 表示分配给当前线程任务,执行到的桶位
// bound 表示分配给当前线程的下界限制
int i = 0, bound = 0;
for (;;) {// 自旋
// f 桶位的头结点 fh 头结点的hash
Node<K,V> f; int fh;
/**
* 1 给当前线程分配区间
* 2 维护当前线程任务进度(i 当前处理的桶位
* 3 维护map对象全局范围内的进度
*/
while (advance) {
// 分配任务区间的变量 nextIndex分配开始的下标 nextBound 结束下标
int nextIndex, nextBound;
// --i>=bound 当前线程任务尚未完成, 还有相应的区间桶位要处理 --i 表示下一个处理的桶位
// 不成立 表示已经完成 或者未分配
// i:表示当前线程在迁移自己范围的数组下标元素t[i]
if (--i >= bound || finishing)
advance = false;
// 前置条件 任务已经完成 或者还没有分配任务
// 条件成立 表示对象全局范围内的桶位都分配完毕了 没有区间分配了
// 设置全局i变量为-1 执行退出迁移相关的程序
// 不成立 全局范围内的桶位尚未分配还有区间可分配
// transferIndex:表示每个线程分配的一段迁移范围的起始下标,比如数组长度32,则第一个线程的transferIndex=16,第二个线程的transferIndex=0
else if ((nextIndex = transferIndex) <= 0) {
i = -1;
advance = false;
}
// 前置条件 当前线程需要分配任务区间 2 【全局范围内的桶位尚未分配还有区间可分配】
// 条件成功 说明给当前任务分配成功
// 失败 就是 说明分配给当前线程失败,可能发生竞争
else if (U.compareAndSetInt
(this, TRANSFERINDEX, nextIndex,
nextBound = (nextIndex > stride ?
nextIndex - stride : 0))) {
// 区间复制给bound
bound = nextBound;
// 【transferIndex,transferIndex+n】区间结尾-1
i = nextIndex - 1;
advance = false; // 结束
}
}
// i<0 的情况 表示当前线程未分配到任务,或任务结束
if (i < 0 || i >= n || i + n >= nextn) {
int sc;// sizeCtl 的临时变量
// finishing = true:扩容结束
if (finishing) {
nextTable = null;
table = nextTab;
sizeCtl = (n << 1) - (n >>> 1);
return;
}
// 迁移退出一个线程
// 条件成立 说明 设置sizeCtl 低16位-1成功 当前线程可以退出
if (U.compareAndSetInt(this, SIZECTL, sc = sizeCtl, sc - 1)) {
//条件成立 说明当前线程不是最后一个退出transfer任务线程
if ((sc - 2) != resizeStamp(n) << RESIZE_STAMP_SHIFT)
// 最后一个线程退出,则return
return;
finishing = advance = true;
i = n; // recheck before commit
}
}
//前置条件
//casr1:成立:说明当前桶没有存放数据 只需要将此处设置为fwd结点
else if ((f = tabAt(tab, i)) == null)
advance = casTabAt(tab, i, null, fwd);
//casr2:条件成立 说明当前桶位已经迁移过了,当前线程不用再处理
// 直接在此更新当前线程任务索引,在处理下一个桶位。
else if ((fh = f.hash) == MOVED)
advance = true; // already processed
// 前置条件 当前桶位有数据 而且node结点不是fwd结点 说明这些数据需要迁移
else {
// sync 加锁当前桶位的头结点
synchronized (f) {
// 防止 在你加锁投之前 头对象被其他线程修改过 导致你加锁对象错误
if (tabAt(tab, i) == f) {
// ln 低位链表 hn 高位链表
Node<K,V> ln, hn;
if (fh >= 0) { // 条件成立表示当前桶位是链表
//lastRun
// 可以获取当前链表 末尾连续高位不变的 node
int runBit = fh & n;
Node<K,V> lastRun = f;
for (Node<K,V> p = f.next; p != null; p = p.next) {
int b = p.hash & n;
if (b != runBit) {
runBit = b;
lastRun = p;
}
}
// 说明 lastRun链表 为低位链表 让ln 引用lastRun
if (runBit == 0) {
ln = lastRun;
hn = null;
}
else {
hn = lastRun;
ln = null;
}
//迭代链表 当循环结点 不等于lastRun
for (Node<K,V> p = f; p != lastRun; p = p.next) {
int ph = p.hash; K pk = p.key; V pv = p.val;
if ((ph & n) == 0)
ln = new Node<K,V>(ph, pk, pv, ln);
else
hn = new Node<K,V>(ph, pk, pv, hn);
}
// 将ln低位节点设置到新链表nextTab的【原旧链表下标i】位置
setTabAt(nextTab, i, ln);
// 将hn高位节点设置到新链表nextTab的【原旧链表下标i+旧链表长度】位置,这里的设置很巧妙,刚好==hash&(n-1)
setTabAt(nextTab, i + n, hn);
// 将旧链表tab的下标i设置fwd元素,表示当前元素迁移完成
setTabAt(tab, i, fwd);
advance = true;
}
// 当前要迁移的节点为红黑树节点,相同的操作,遍历红黑树找出低位和高位节点,然后链接到新hash表中
else if (f instanceof TreeBin) {
// 转换头结点为treeBin 引用
TreeBin<K,V> t = (TreeBin<K,V>)f;
// 低位双向链表+
TreeNode<K,V> lo = null, loTail = null;
TreeNode<K,V> hi = null, hiTail = null;
int lc = 0, hc = 0;
for (Node<K,V> e = t.first; e != null; e = e.next) {
int h = e.hash;
TreeNode<K,V> p = new TreeNode<K,V>
(h, e.key, e.val, null, null);
if ((h & n) == 0) {
if ((p.prev = loTail) == null)
lo = p;
else
loTail.next = p;
loTail = p;
++lc;
}
else {
if ((p.prev = hiTail) == null)
hi = p;
else
hiTail.next = p;
hiTail = p;
++hc;
}
}
ln = (lc <= UNTREEIFY_THRESHOLD) ? untreeify(lo) :
(hc != 0) ? new TreeBin<K,V>(lo) : t;
hn = (hc <= UNTREEIFY_THRESHOLD) ? untreeify(hi) :
(lc != 0) ? new TreeBin<K,V>(hi) : t;
setTabAt(nextTab, i, ln);
setTabAt(nextTab, i + n, hn);
setTabAt(tab, i, fwd);
advance = true;
}
}
}
}
}
}
public V get(Object key) {
// tab 引用map.table
// e 当前元素
// p 目标结点
// n 长度
// eh 当前元素的hash
// ek 当前元素的key
Node<K,V>[] tab; Node<K,V> e, p; int n, eh; K ek;
int h = spread(key.hashCode());// 通过扰动运算后得到 更散列的hash值
// 表已经创建了 而且头结点不等于null
if ((tab = table) != null && (n = tab.length) > 0 &&
(e = tabAt(tab, (n - 1) & h)) != null) {
// 头结点直接找到
if ((eh = e.hash) == h) {
if ((ek = e.key) == key || (ek != null && key.equals(ek)))
return e.val;
}
// -1 fwd结点说明table正在扩容 且当前查询的已经被迁移走了
// -2 Treebin 需要使用Treebin方法查询
else if (eh < 0)
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;
}
public V remove(Object key) {
return replaceNode(key, null, null);
}
final V replaceNode(Object key, V value, Object cv) {
int hash = spread(key.hashCode());
for (Node<K,V>[] tab = table;;) {
Node<K,V> f; int n, i, fh;
if (tab == null || (n = tab.length) == 0 ||
(f = tabAt(tab, i = (n - 1) & hash)) == null)
break;
else if ((fh = f.hash) == MOVED)
tab = helpTransfer(tab, f);
else {
V oldVal = null;
boolean validated = false;
synchronized (f) {
if (tabAt(tab, i) == f) {
if (fh >= 0) {
validated = true;
for (Node<K,V> e = f, pred = null;;) {
K ek;
if (e.hash == hash &&
((ek = e.key) == key ||
(ek != null && key.equals(ek)))) {
V ev = e.val;
if (cv == null || cv == ev ||
(ev != null && cv.equals(ev))) {
oldVal = ev;
if (value != null)
e.val = value;
else if (pred != null)
pred.next = e.next;
else
setTabAt(tab, i, e.next);
}
break;
}
pred = e;
if ((e = e.next) == null)
break;
}
}
else if (f instanceof TreeBin) {
validated = true;
TreeBin<K,V> t = (TreeBin<K,V>)f;
TreeNode<K,V> r, p;
if ((r = t.root) != null &&
(p = r.findTreeNode(hash, key, null)) != null) {
V pv = p.val;
if (cv == null || cv == pv ||
(pv != null && cv.equals(pv))) {
oldVal = pv;
if (value != null)
p.val = value;
else if (t.removeTreeNode(p))
setTabAt(tab, i, untreeify(t.first));
}
}
}
else if (f instanceof ReservationNode)
throw new IllegalStateException("Recursive update");
}
}
if (validated) {
if (oldVal != null) {
if (value == null)
// 扩容,可能将红黑树转为链表
addCount(-1L, -1);
return oldVal;
}
break;
}
}
}
return null;
}