diff --git a/src/java/lang/Integer.java b/src/java/lang/Integer.java
index 63f5069c..6f3387a3 100644
--- a/src/java/lang/Integer.java
+++ b/src/java/lang/Integer.java
@@ -1292,8 +1292,7 @@ public static int remainderUnsigned(int dividend, int divisor) {
// Bit twiddling
/**
- * The number of bits used to represent an {@code int} value in two's
- * complement binary form.
+ * The number of bits used to represent an {@code int} value in 二进制补码.
*
* @since 1.5
*/
@@ -1349,11 +1348,7 @@ public static int lowestOneBit(int i) {
}
/**
- * Returns the number of zero bits preceding the highest-order
- * ("leftmost") one-bit in the two's complement binary representation
- * of the specified {@code int} value. Returns 32 if the
- * specified value has no one-bits in its two's complement representation,
- * in other words if it is equal to zero.
+ * 入参的二进制补码左边0的数量 如果入参是0那么结果就是32.
*
*
Note that this method is closely related to the logarithm base 2.
* For all positive {@code int} values x:
@@ -1371,8 +1366,9 @@ public static int lowestOneBit(int i) {
*/
public static int numberOfLeadingZeros(int i) {
// HD, Figure 5-6
- if (i == 0)
+ if (i == 0) {
return 32;
+ }
int n = 1;
if (i >>> 16 == 0) { n += 16; i <<= 16; }
if (i >>> 24 == 0) { n += 8; i <<= 8; }
diff --git a/src/java/lang/Thread.java b/src/java/lang/Thread.java
index 3da9770f..8f0abc15 100644
--- a/src/java/lang/Thread.java
+++ b/src/java/lang/Thread.java
@@ -383,19 +383,21 @@ private void init(ThreadGroup g, Runnable target, String name,
this.daemon = parent.isDaemon();
// 子线程继承父线程的优先级属性
this.priority = parent.getPriority();
- if (security == null || isCCLOverridden(parent.getClass()))
+ if (security == null || isCCLOverridden(parent.getClass())) {
this.contextClassLoader = parent.getContextClassLoader();
- else
+ } else {
this.contextClassLoader = parent.contextClassLoader;
+ }
this.inheritedAccessControlContext =
acc != null ? acc : AccessController.getContext();
this.target = target;
setPriority(priority);
// 当父线程的 inheritableThreadLocals 的值不为空时
// 会把 inheritableThreadLocals 里面的值全部传递给子线程
- if (inheritThreadLocals && parent.inheritableThreadLocals != null)
+ if (inheritThreadLocals && parent.inheritableThreadLocals != null) {
this.inheritableThreadLocals =
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
+ }
/* Stash the specified stack size in case the VM cares */
this.stackSize = stackSize;
@@ -667,8 +669,9 @@ public Thread(ThreadGroup group, Runnable target, String name,
*/
public synchronized void start() {
// 如果没有初始化,抛异常
- if (threadStatus != 0)
+ if (threadStatus != 0) {
throw new IllegalThreadStateException();
+ }
// 将当前线程加入到所在的线程组,记录为活跃线程
group.add(this);
@@ -844,8 +847,9 @@ public final synchronized void stop(Throwable obj) {
*/
public void interrupt() {
// 如果由别的线程对当前线程发起中断
- if (this != Thread.currentThread())
+ if (this != Thread.currentThread()) {
checkAccess();
+ }
synchronized (blockerLock) {
Interruptible b = blocker;
@@ -1243,6 +1247,7 @@ public final void checkAccess() {
*
* @return 该线程的字符串表示
*/
+ @Override
public String toString() {
ThreadGroup group = getThreadGroup();
if (group != null) {
@@ -1264,8 +1269,9 @@ public String toString() {
*/
@CallerSensitive
public ClassLoader getContextClassLoader() {
- if (contextClassLoader == null)
+ if (contextClassLoader == null) {
return null;
+ }
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
ClassLoader.checkClassLoaderPermission(contextClassLoader,
@@ -1401,8 +1407,9 @@ private static class Caches {
* "enableContextClassLoaderOverride" RuntimePermission is checked.
*/
private static boolean isCCLOverridden(Class> cl) {
- if (cl == Thread.class)
+ if (cl == Thread.class) {
return false;
+ }
processQueue(Caches.subclassAuditsQueue, Caches.subclassAudits);
WeakClassKey key = new WeakClassKey(cl, Caches.subclassAuditsQueue);
@@ -1423,6 +1430,7 @@ private static boolean isCCLOverridden(Class> cl) {
private static boolean auditSubclass(final Class> subcl) {
Boolean result = AccessController.doPrivileged(
new PrivilegedAction() {
+ @Override
public Boolean run() {
for (Class> cl = subcl;
cl != Thread.class;
@@ -1486,6 +1494,7 @@ public enum State {
/**
* 运行中的线程
+ * RUNNABLE_READY调用start方法 RUNNABLE_RUNNING调用run方法
*/
RUNNABLE,
@@ -1698,8 +1707,9 @@ public int hashCode() {
*/
@Override
public boolean equals(Object obj) {
- if (obj == this)
+ if (obj == this) {
return true;
+ }
if (obj instanceof WeakClassKey) {
Object referent = get();
diff --git a/src/java/lang/ThreadGroup.java b/src/java/lang/ThreadGroup.java
index 1d957362..6d03a714 100644
--- a/src/java/lang/ThreadGroup.java
+++ b/src/java/lang/ThreadGroup.java
@@ -1047,6 +1047,7 @@ void list(PrintStream out, int indent) {
* @param e the uncaught exception.
* @since JDK1.0
*/
+ @Override
public void uncaughtException(Thread t, Throwable e) {
if (parent != null) {
parent.uncaughtException(t, e);
diff --git a/src/java/lang/ThreadLocal.java b/src/java/lang/ThreadLocal.java
index 72610902..43d79314 100644
--- a/src/java/lang/ThreadLocal.java
+++ b/src/java/lang/ThreadLocal.java
@@ -324,8 +324,9 @@ private ThreadLocalMap(ThreadLocalMap parentMap) {
Object value = key.childValue(e.value);
Entry c = new Entry(key, value);
int h = key.threadLocalHashCode & (len - 1);
- while (table[h] != null)
+ while (table[h] != null) {
h = nextIndex(h, len);
+ }
table[h] = c;
size++;
}
@@ -466,11 +467,16 @@ private void replaceStaleEntry(ThreadLocal> key, Object value,
// incremental rehashing due to garbage collector freeing
// up refs in bunches (i.e., whenever the collector runs).
int slotToExpunge = staleSlot;
+ // 往左找直到遇到空插孔
for (int i = prevIndex(staleSlot, len);
(e = tab[i]) != null;
- i = prevIndex(i, len))
- if (e.get() == null)
+ i = prevIndex(i, len)) {
+ // 如果遇到垃圾值
+ if (e.get() == null) {
+ // 垃圾值所在插孔下标记作slotToExpunge
slotToExpunge = i;
+ }
+ }
// Find either the key or trailing null slot of run, whichever
// occurs first
@@ -491,8 +497,9 @@ private void replaceStaleEntry(ThreadLocal> key, Object value,
tab[staleSlot] = e;
// Start expunge at preceding stale entry if it exists
- if (slotToExpunge == staleSlot)
+ if (slotToExpunge == staleSlot) {
slotToExpunge = i;
+ }
cleanSomeSlots(expungeStaleEntry(slotToExpunge), len);
return;
}
@@ -500,8 +507,9 @@ private void replaceStaleEntry(ThreadLocal> key, Object value,
// If we didn't find stale entry on backward scan, the
// first stale entry seen while scanning for key is the
// first still present in the run.
- if (k == null && slotToExpunge == staleSlot)
+ if (k == null && slotToExpunge == staleSlot) {
slotToExpunge = i;
+ }
}
// If key not found, put new entry in stale slot
@@ -509,8 +517,9 @@ private void replaceStaleEntry(ThreadLocal> key, Object value,
tab[staleSlot] = new Entry(key, value);
// If there are any other stale entries in run, expunge them
- if (slotToExpunge != staleSlot)
+ if (slotToExpunge != staleSlot) {
cleanSomeSlots(expungeStaleEntry(slotToExpunge), len);
+ }
}
/**
@@ -547,8 +556,9 @@ private int expungeStaleEntry(int staleSlot) {
// Unlike Knuth 6.4 Algorithm R, we must scan until
// null because multiple entries could have been stale.
- while (tab[h] != null)
+ while (tab[h] != null) {
h = nextIndex(h, len);
+ }
tab[h] = e;
}
}
@@ -605,8 +615,9 @@ private void rehash() {
expungeStaleEntries();
// Use lower threshold for doubling to avoid hysteresis
- if (size >= threshold - threshold / 4)
+ if (size >= threshold - threshold / 4) {
resize();
+ }
}
/**
@@ -654,8 +665,9 @@ private void expungeStaleEntries() {
int len = tab.length;
for (int j = 0; j < len; j++) {
Entry e = tab[j];
- if (e != null && e.get() == null)
+ if (e != null && e.get() == null) {
expungeStaleEntry(j);
+ }
}
}
}
diff --git a/src/java/util/ArrayList.java b/src/java/util/ArrayList.java
index a3c96265..65a14436 100644
--- a/src/java/util/ArrayList.java
+++ b/src/java/util/ArrayList.java
@@ -435,8 +435,10 @@ public E remove(int index) {
int numMoved = size - index - 1;
if (numMoved > 0)
// 将elementData数组index+1位置开始拷贝到elementData从index开始的空间
+ {
System.arraycopy(elementData, index + 1, elementData, index,
numMoved);
+ }
// 使size-1 ,设置elementData的size位置为空,让GC来清理内存空间
elementData[--size] = null; //便于垃圾回收器回收
@@ -769,28 +771,33 @@ private class Itr implements Iterator {
int expectedModCount = modCount;//迭代过程不运行修改数组,否则就抛出异常
//是否还有下一个
+ @Override
public boolean hasNext() {
return cursor != size;
}
//下一个元素
+ @Override
@SuppressWarnings("unchecked")
public E next() {
- checkForComodification();//检查数组是否被修改
+ checkForComodification();// 检查数组是否被修改
int i = cursor;
- if (i >= size)
+ if (i >= size) {
throw new NoSuchElementException();
+ }
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
- cursor = i + 1;//向后移动游标
- return (E) elementData[lastRet = i];//设置访问的位置并返回这个值
+ cursor = i + 1;// 向后移动游标
+ return (E) elementData[lastRet = i];// 设置访问的位置并返回这个值
}
//删除元素
+ @Override
public void remove() {
- if (lastRet < 0)
+ if (lastRet < 0) {
throw new IllegalStateException();
+ }
checkForComodification();//检查数组是否被修改
try {
@@ -827,8 +834,9 @@ public void forEachRemaining(Consumer super E> consumer) {
//检查数组是否被修改
final void checkForComodification() {
- if (modCount != expectedModCount)
+ if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
+ }
}
}
@@ -841,34 +849,42 @@ private class ListItr extends Itr implements ListIterator {
cursor = index;
}
+ @Override
public boolean hasPrevious() {
return cursor != 0;
}
+ @Override
public int nextIndex() {
return cursor;
}
+ @Override
public int previousIndex() {
return cursor - 1;
}
+ @Override
@SuppressWarnings("unchecked")
public E previous() {
checkForComodification();
int i = cursor - 1;
- if (i < 0)
+ if (i < 0) {
throw new NoSuchElementException();
+ }
Object[] elementData = ArrayList.this.elementData;
- if (i >= elementData.length)
+ if (i >= elementData.length) {
throw new ConcurrentModificationException();
+ }
cursor = i;
return (E) elementData[lastRet = i];
}
+ @Override
public void set(E e) {
- if (lastRet < 0)
+ if (lastRet < 0) {
throw new IllegalStateException();
+ }
checkForComodification();
try {
@@ -878,6 +894,7 @@ public void set(E e) {
}
}
+ @Override
public void add(E e) {
checkForComodification();
diff --git a/src/java/util/HashMap.java b/src/java/util/HashMap.java
index bdebd912..16334c56 100644
--- a/src/java/util/HashMap.java
+++ b/src/java/util/HashMap.java
@@ -660,9 +660,10 @@ public void putAll(Map extends K, ? extends V> m) {
* @param key 参数key
* @return 如果没有映射到node,返回null,否则返回对应的value
*/
+ @Override
public V remove(Object key) {
Node e;
- //根据key来删除node。removeNode方法的具体实现在下面
+ // 根据key来删除node。removeNode方法的具体实现在下面
return (e = removeNode(hash(key), key, null, false, true)) == null ?
null : e.value;
}
diff --git a/src/java/util/HashSet.java b/src/java/util/HashSet.java
index fbc106e5..659d1e8b 100644
--- a/src/java/util/HashSet.java
+++ b/src/java/util/HashSet.java
@@ -232,6 +232,7 @@ public boolean add(E e) {
* @param o object to be removed from this set, if present
* @return true if the set contained the specified element
*/
+ @Override
public boolean remove(Object o) {
return map.remove(o)==PRESENT;
}
diff --git a/src/java/util/LinkedHashMap.java b/src/java/util/LinkedHashMap.java
index bd06d86f..5f25d864 100644
--- a/src/java/util/LinkedHashMap.java
+++ b/src/java/util/LinkedHashMap.java
@@ -190,6 +190,7 @@ public class LinkedHashMap
* HashMap.Node subclass for normal LinkedHashMap entries.
*/
static class Entry extends HashMap.Node {
+ // 双向链表
Entry before, after;
Entry(int hash, K key, V value, Node next) {
super(hash, key, value, next);
@@ -218,13 +219,15 @@ static class Entry extends HashMap.Node {
// internal utilities
- // link at the end of list
+ // link at the end of list 把新节点连接到链表尾部
private void linkNodeLast(LinkedHashMap.Entry p) {
LinkedHashMap.Entry last = tail;
tail = p;
- if (last == null)
+ // 尾巴没有 头也没有? 所以 新节点就是头
+ if (last == null) {
head = p;
- else {
+ } else {
+ // 否则新节点的前一个节点是之前的尾巴
p.before = last;
last.after = p;
}
@@ -255,6 +258,7 @@ void reinitialize() {
Node newNode(int hash, K key, V value, Node e) {
LinkedHashMap.Entry p =
new LinkedHashMap.Entry(hash, key, value, e);
+ //
linkNodeLast(p);
return p;
}
diff --git a/src/java/util/ListIterator.java b/src/java/util/ListIterator.java
index 5150f4f1..364befdf 100644
--- a/src/java/util/ListIterator.java
+++ b/src/java/util/ListIterator.java
@@ -147,6 +147,7 @@ public interface ListIterator extends Iterator {
* {@code add} have been called after the last call to
* {@code next} or {@code previous}
*/
+ @Override
void remove();
/**
diff --git a/src/java/util/concurrent/ArrayBlockingQueue.java b/src/java/util/concurrent/ArrayBlockingQueue.java
index 2e8b761b..919dfb4f 100644
--- a/src/java/util/concurrent/ArrayBlockingQueue.java
+++ b/src/java/util/concurrent/ArrayBlockingQueue.java
@@ -159,8 +159,9 @@ private void enqueue(E x) {
// assert items[putIndex] == null;
final Object[] items = this.items;
items[putIndex] = x;
- if (++putIndex == items.length)
+ if (++putIndex == items.length) {
putIndex = 0;
+ }
count++;
notEmpty.signal();
}
@@ -321,14 +322,15 @@ public boolean add(E e) {
*
* @throws NullPointerException if the specified element is null
*/
+ @Override
public boolean offer(E e) {
checkNotNull(e);
final ReentrantLock lock = this.lock;
lock.lock();
try {
- if (count == items.length)
+ if (count == items.length) {
return false;
- else {
+ } else {
enqueue(e);
return true;
}
@@ -395,26 +397,34 @@ public E poll() {
}
}
+ @Override
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
- while (count == 0)
+ while (count == 0) {
notEmpty.await();
+ }
return dequeue();
} finally {
lock.unlock();
}
}
+ @Override
public E poll(long timeout, TimeUnit unit) throws InterruptedException {
+ // 和时间单位组合一下变成纳秒
long nanos = unit.toNanos(timeout);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
+ // 队列里没有了
while (count == 0) {
- if (nanos <= 0)
+ // 等够超时时间就return null
+ if (nanos <= 0) {
return null;
+ }
+ // 等待timeout时间
nanos = notEmpty.awaitNanos(nanos);
}
return dequeue();
diff --git a/src/java/util/concurrent/BlockingDeque.java b/src/java/util/concurrent/BlockingDeque.java
index dd23eb34..b2253ec2 100644
--- a/src/java/util/concurrent/BlockingDeque.java
+++ b/src/java/util/concurrent/BlockingDeque.java
@@ -466,6 +466,7 @@ E pollLast(long timeout, TimeUnit unit)
* @throws IllegalArgumentException if some property of the specified
* element prevents it from being added to this deque
*/
+ @Override
boolean offer(E e);
/**
diff --git a/src/java/util/concurrent/BlockingQueue.java b/src/java/util/concurrent/BlockingQueue.java
index 5110d62b..fd70503a 100644
--- a/src/java/util/concurrent/BlockingQueue.java
+++ b/src/java/util/concurrent/BlockingQueue.java
@@ -215,6 +215,7 @@ public interface BlockingQueue extends Queue {
* @throws IllegalArgumentException if some property of the specified
* element prevents it from being added to this queue
*/
+ @Override
boolean offer(E e);
/**
diff --git a/src/java/util/concurrent/ConcurrentHashMap.java b/src/java/util/concurrent/ConcurrentHashMap.java
index 0b6047ba..eb9a48f4 100644
--- a/src/java/util/concurrent/ConcurrentHashMap.java
+++ b/src/java/util/concurrent/ConcurrentHashMap.java
@@ -12,8 +12,8 @@
import java.util.stream.Stream;
-public class ConcurrentHashMap extends AbstractMap
- implements ConcurrentMap, Serializable {
+public class ConcurrentHashMap extends AbstractMap implements ConcurrentMap, Serializable {
+
private static final long serialVersionUID = 7249069246763182397L;
@@ -62,10 +62,10 @@ public class ConcurrentHashMap extends AbstractMap
static final int MIN_TREEIFY_CAPACITY = 64;
/**
- * Minimum number of rebinnings per transfer step. Ranges are
- * subdivided to allow multiple resizer threads. This value
- * serves as a lower bound to avoid resizers encountering
- * excessive memory contention. The value should be at least
+ * 每次转移元素最少是16个格子. Ranges are
+ * subdivided to allow multiple resizer threads.
+ * 这个值用来避免过度的内存争用 避免过多的CPU空转
+ * . The value should be at least
* DEFAULT_CAPACITY.
*/
private static final int MIN_TRANSFER_STRIDE = 16;
@@ -90,8 +90,15 @@ public class ConcurrentHashMap extends AbstractMap
* Encodings for Node hash fields. See above for explanation.
*/
static final int MOVED = -1; // hash for forwarding nodes (forwarding nodes的hash值)、标示位
+
static final int TREEBIN = -2; // hash值是-2 表示这是一个TreeBin节点
- static final int RESERVED = -3; // hash for transient reservations
+
+ static final int RESERVED = -3; // hash for 序列化预留的值
+
+ /**
+ * Integer.MAX_VALUE
+ * 01111111 11111111 11111111 11111111
+ */
static final int HASH_BITS = 0x7fffffff; // usable bits of normal node hash (ReservationNode的hash值)
/**
@@ -102,11 +109,9 @@ public class ConcurrentHashMap extends AbstractMap
/**
* For serialization compatibility.
*/
- private static final ObjectStreamField[] serialPersistentFields = {
- new ObjectStreamField("segments", Segment[].class),
- new ObjectStreamField("segmentMask", Integer.TYPE),
- new ObjectStreamField("segmentShift", Integer.TYPE)
- };
+ private static final ObjectStreamField[] serialPersistentFields = { new ObjectStreamField("segments",
+ Segment[].class), new ObjectStreamField(
+ "segmentMask", Integer.TYPE), new ObjectStreamField("segmentShift", Integer.TYPE) };
/* ---------------- Nodes -------------- */
@@ -116,10 +121,14 @@ public class ConcurrentHashMap extends AbstractMap
* 它不允许调用setValue方法直接改变Node的value域,它增加了find方法辅助map.get()方法。
*/
static class Node implements Map.Entry {
+
final int hash;
+
final K key;
+
//val和next都会在扩容时发生变化,所以加上volatile来保持可见性和禁止重排序
volatile V val;
+
volatile Node next;
Node(int hash, K key, V val, Node next) {
@@ -129,10 +138,12 @@ static class Node implements Map.Entry {
this.next = next;
}
+ @Override
public final K getKey() {
return key;
}
+ @Override
public final V getValue() {
return val;
}
@@ -157,14 +168,12 @@ public final V setValue(V value) {
/**
* HashMap使用if (o == this),且嵌套if;ConcurrentHashMap使用&&
*/
+ @Override
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)));
+ 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)));
}
/**
@@ -175,8 +184,7 @@ Node find(int h, Object k) {
if (k != null) {
do {
K ek;
- if (e.hash == h &&
- ((ek = e.key) == k || (ek != null && k.equals(ek))))
+ if (e.hash == h && ((ek = e.key) == k || (ek != null && k.equals(ek))))
return e;
} while ((e = e.next) != null);
}
@@ -190,6 +198,8 @@ Node find(int h, Object k) {
* 对hashCode进行再散列,算法为(h ^ (h >>> 16)) & HASH_BITS
*/
static final int spread(int h) {
+ // HASH_BITS二进制最高位是0 &HASH_BITS 只是为了保证第一位是0 保证hash值是正数
+ // h ^ (h >>> 16) 高16位右移异或 去扰动低16位 降低hash冲突
return (h ^ (h >>> 16)) & HASH_BITS;
}
@@ -209,6 +219,7 @@ private static final int tableSizeFor(int c) {
/**
* Returns x's Class if it is of the form "class C implements
* Comparable", else null.
+ * 看一下key是否可以比较
*/
static Class> comparableClassFor(Object x) {
if (x instanceof Comparable) {
@@ -216,16 +227,17 @@ static Class> comparableClassFor(Object x) {
Type[] ts, as;
Type t;
ParameterizedType p;
+ // String则直接返回Class
if ((c = x.getClass()) == String.class) // bypass checks
+ {
return c;
+ }
if ((ts = c.getGenericInterfaces()) != null) {
for (int i = 0; i < ts.length; ++i) {
- if (((t = ts[i]) instanceof ParameterizedType) &&
- ((p = (ParameterizedType) t).getRawType() ==
- Comparable.class) &&
- (as = p.getActualTypeArguments()) != null &&
- as.length == 1 && as[0] == c) // type arg is c
+ if (((t = ts[i]) instanceof ParameterizedType) && ((p = (ParameterizedType) t).getRawType() == Comparable.class) && (as = p.getActualTypeArguments()) != null && as.length == 1 && as[0] == c) // type arg is c
+ {
return c;
+ }
}
}
}
@@ -236,10 +248,10 @@ static Class> comparableClassFor(Object x) {
* Returns k.compareTo(x) if x matches kc (k's screened comparable
* class), else 0.
*/
- @SuppressWarnings({"rawtypes", "unchecked"}) // for cast to Comparable
+ @SuppressWarnings( { "rawtypes", "unchecked" }) // for cast to Comparable
static int compareComparables(Class> kc, Object k, Object x) {
- return (x == null || x.getClass() != kc ? 0 :
- ((Comparable) k).compareTo(x));
+ // 父节点是null 或者 父节点的class和如惨k的class不一样 则返回0 能比较就比一下
+ return (x == null || x.getClass() != kc ? 0 : ((Comparable) k).compareTo(x));
}
/* ---------------- Table element access -------------- */
@@ -265,14 +277,15 @@ static int compareComparables(Class> kc, Object k, Object x) {
*/
@SuppressWarnings("unchecked")
static final Node tabAt(Node[] tab, int i) {
+ // 2i+16
return (Node) U.getObjectVolatile(tab, ((long) i << ASHIFT) + ABASE);
}
/**
* 利用CAS算法设置i位置上的Node节点(将c和table[i]比较,相同则插入v)。
+ * ASHIFT = 2 ABASE = 16 其实我看不太懂
*/
- static final boolean casTabAt(Node[] tab, int i,
- Node c, Node v) {
+ static final boolean casTabAt(Node[] tab, int i, Node c, Node v) {
return U.compareAndSwapObject(tab, ((long) i << ASHIFT) + ABASE, c, v);
}
@@ -305,7 +318,7 @@ static final void setTabAt(Node[] tab, int i, Node v) {
* 正数或0代表hash表还没有被初始化,这个数值表示初始化或下一次进行扩容的大小,类似于扩容阈值。
* 它的值始终是当前ConcurrentHashMap容量的0.75倍,这与loadfactor是对应的。实际容量>=sizeCtl,则扩容。
*/
- private transient volatile int sizeCtl;//控制标识符
+ private transient volatile int sizeCtl;// 控制标识符
/**
* The next table index (plus one) to split while resizing.
@@ -325,7 +338,9 @@ static final void setTabAt(Node[] tab, int i, Node v) {
// views
private transient KeySetView keySet;
+
private transient ValuesView values;
+
private transient EntrySetView entrySet;
@@ -341,15 +356,15 @@ public ConcurrentHashMap() {
* 指定容量的构造函数
*
* @param initialCapacity 初始化容量
+ *
* @throws IllegalArgumentException if the initial capacity of
* elements is negative
*/
public ConcurrentHashMap(int initialCapacity) {
if (initialCapacity < 0)
throw new IllegalArgumentException();
- int cap = ((initialCapacity >= (MAXIMUM_CAPACITY >>> 1)) ?
- MAXIMUM_CAPACITY :
- tableSizeFor(initialCapacity + (initialCapacity >>> 1) + 1));
+ int cap = ((initialCapacity >= (MAXIMUM_CAPACITY >>> 1)) ? MAXIMUM_CAPACITY : tableSizeFor(
+ initialCapacity + (initialCapacity >>> 1) + 1));
this.sizeCtl = cap;//初始化sizeCtl
}
@@ -370,6 +385,7 @@ public ConcurrentHashMap(Map extends K, ? extends V> m) {
*
* @param initialCapacity 初始容量
* @param loadFactor 负载因子,当容量达到initialCapacity*loadFactor时,执行扩容
+ *
* @throws IllegalArgumentException if the initial capacity of
* elements is negative or the load factor is nonpositive
* @since 1.6
@@ -387,19 +403,18 @@ public ConcurrentHashMap(int initialCapacity, float loadFactor) {
* @param initialCapacity 初始容量
* @param loadFactor 负载因子,当容量达到initialCapacity*loadFactor时,执行扩容
* @param concurrencyLevel 预估的并发更新线程数
+ *
* @throws IllegalArgumentException if the initial capacity is
* negative or the load factor or concurrencyLevel are
* nonpositive
*/
- public ConcurrentHashMap(int initialCapacity,
- float loadFactor, int concurrencyLevel) {
+ public ConcurrentHashMap(int initialCapacity, float loadFactor, int concurrencyLevel) {
if (!(loadFactor > 0.0f) || initialCapacity < 0 || concurrencyLevel <= 0)
throw new IllegalArgumentException();
if (initialCapacity < concurrencyLevel) // Use at least as many bins
initialCapacity = concurrencyLevel; // as estimated threads
long size = (long) (1.0 + (long) initialCapacity / loadFactor);
- int cap = (size >= (long) MAXIMUM_CAPACITY) ?
- MAXIMUM_CAPACITY : tableSizeFor((int) size);
+ int cap = (size >= (long) MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : tableSizeFor((int) size);
this.sizeCtl = cap;
}
@@ -408,16 +423,16 @@ public ConcurrentHashMap(int initialCapacity,
/**
* {@inheritDoc}
*/
+ @Override
public int size() {
long n = sumCount();
- return ((n < 0L) ? 0 :
- (n > (long) Integer.MAX_VALUE) ? Integer.MAX_VALUE :
- (int) n);
+ return ((n < 0L) ? 0 : (n > (long) Integer.MAX_VALUE) ? Integer.MAX_VALUE : (int) n);
}
/**
* {@inheritDoc}
*/
+ @Override
public boolean isEmpty() {
return sumCount() <= 0L; // ignore transient negative values
}
@@ -429,6 +444,7 @@ public boolean isEmpty() {
*
* @throws NullPointerException if the specified key is null
*/
+ @Override
public V get(Object key) {
Node[] tab;
Node e, p;
@@ -436,19 +452,21 @@ public V get(Object key) {
K ek;
int h = spread(key.hashCode());//两次hash计算出hash值
//根据hash值确定节点位置
- if ((tab = table) != null && (n = tab.length) > 0 &&
- (e = tabAt(tab, (n - 1) & h)) != null) {
+ if ((tab = table) != null && (n = tab.length) > 0 && (e = tabAt(tab, (n - 1) & h)) != null) {
// 搜索到的节点key与传入的key相同且不为null,直接返回这个节点
if ((eh = e.hash) == h) {
- if ((ek = e.key) == key || (ek != null && key.equals(ek)))
+ if ((ek = e.key) == key || (ek != null && key.equals(ek))) {
return e.val;
+ }
} else if (eh < 0)//如果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))))
+ if (e.hash == h && ((ek = e.key) == key || (ek != null && key.equals(ek)))) {
return e.val;
+ }
}
}
return null;
@@ -458,11 +476,13 @@ public V get(Object key) {
* 检查table中是否含有key
*
* @param key possible key
+ *
* @return {@code true} if and only if the specified object
* is a key in this table, as determined by the
* {@code equals} method; {@code false} otherwise
* @throws NullPointerException if the specified key is null
*/
+ @Override
public boolean containsKey(Object key) {
//直接调用get(int key)方法即可,如果有返回值,则说明是包含key的
return get(key) != null;
@@ -473,6 +493,7 @@ public boolean containsKey(Object key) {
* 这个方法可能需要完全遍历Map,因此比containsKey要慢的多
*
* @param value value whose presence in this map is to be tested
+ *
* @return {@code true} if this map maps one or more keys to the
* specified value
* @throws NullPointerException if the specified value is null
@@ -497,10 +518,12 @@ public boolean containsValue(Object value) {
*
* @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
*/
+ @Override
public V put(K key, V value) {
return putVal(key, value, false);
}
@@ -520,70 +543,94 @@ public V put(K key, V value) {
* 5、如果table[i]的节点是链表节点,则检查table的第i个位置的链表是否需要转化为数,如果需要则调用treeifyBin函数进行转化
*/
final V putVal(K key, V value, boolean onlyIfAbsent) {
- if (key == null || value == null) throw new NullPointerException();// key和value不允许null
- int hash = spread(key.hashCode());//两次hash,减少hash冲突,可以均匀分布
- int binCount = 0;//i处结点标志,0: 未加入新结点, 2: TreeBin或链表结点数, 其它:链表结点数。主要用于每次加入结点后查看是否要由链表转为红黑树
- for (Node[] tab = table; ; ) {//CAS经典写法,不成功无限重试
+ // key和value不允许null
+ if (key == null || value == null) {
+ throw new NullPointerException();
+ }
+ // 两次hash,减少hash冲突,可以均匀分布
+ int hash = spread(key.hashCode());
+ // 插孔节点数标志
+ int binCount = 0;// i处结点标志,0: 未加入新结点, 2: TreeBin或链表结点数, 其它:链表结点数。主要用于每次加入结点后查看是否要由链表转为红黑树
+ for (Node[] tab = table; ; ) {// CAS经典写法,不成功无限重试
Node f;
int n, i, fh;
- //检查是否初始化了,如果没有,则初始化
- if (tab == null || (n = tab.length) == 0)
+ // 检查是否初始化了,如果没有,则初始化
+ if (tab == null || (n = tab.length) == 0) {
tab = initTable();
- /**
+ }
+ /*
* i=(n-1)&hash 等价于i=hash%n(前提是n为2的幂次方).即取出table中位置的节点用f表示。 有如下两种情况:
* 1、如果table[i]==null(即该位置的节点为空,没有发生碰撞),则利用CAS操作直接存储在该位置, 如果CAS操作成功则退出死循环。
* 2、如果table[i]!=null(即该位置已经有其它节点,发生碰撞)
*/
- else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
- if (casTabAt(tab, i, null,
- new Node(hash, key, value, null)))
+ else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) { // 如果插孔是空的
+ // 则通过cas往插孔里面放一个新节点 放不进去会通过上面的for循环一直往里放 直到某个线程放进去了
+ if (casTabAt(tab, i, null, new Node(hash, key, value, null))) {
break; // no lock when adding to empty bin
- } else if ((fh = f.hash) == MOVED)//检查table[i]的节点的hash是否等于MOVED,如果等于,则检测到正在扩容,则帮助其扩容
+ }
+ }
+ // 检查头节点是不是fwd
+ else if ((fh = f.hash) == MOVED)// 检查table[i]的节点的hash是否等于MOVED,如果等于,则检测到正在扩容,则帮助其扩容
+ {
tab = helpTransfer(tab, f);
- else {//table[i]的节点的hash值不等于MOVED。
+ } else {// table[i]的节点的hash值不等于MOVED。
V oldVal = null;
// 针对首个节点进行加锁操作,而不是segment,进一步减少线程冲突
synchronized (f) {
+ // 确认一下头节点是否变化 防止抢到头节点已经被别的线程改过了
if (tabAt(tab, i) == f) {
+ // first hash 再次通过头节点hash确认 这个插孔不是正在迁移的插孔
+ // 只有链表大于0?
if (fh >= 0) {
+ // 进来啦
binCount = 1;
for (Node e = f; ; ++binCount) {
K ek;
// 如果在链表中找到值为key的节点e,直接设置e.val = value即可
- if (e.hash == hash &&
- ((ek = e.key) == key ||
- (ek != null && key.equals(ek)))) {
+ if (e.hash == hash && ((ek = e.key) == key || (ek != null && key.equals(ek)))) {
+ // 记录老值
oldVal = e.val;
- if (!onlyIfAbsent)
+ // 如果可以覆盖
+ if (!onlyIfAbsent) {
+ // 覆盖老值
e.val = value;
+ }
+ // 覆盖后跳出循环
break;
}
// 如果没有找到值为key的节点,直接新建Node并加入链表即可
Node pred = e;
if ((e = e.next) == null) {//插入到链表末尾并跳出循环
- pred.next = new Node(hash, key,
- value, null);
+ pred.next = new Node(hash, key, value, null);
break;
}
}
- } else if (f instanceof TreeBin) {// 如果首节点为TreeBin类型,说明为红黑树结构,执行putTreeVal操作
+ }
+ // 红黑树节点
+ else if (f instanceof TreeBin) {// 如果首节点为TreeBin类型,说明为红黑树结构,执行putTreeVal操作
Node p;
binCount = 2;
- if ((p = ((TreeBin) f).putTreeVal(hash, key,
- value)) != null) {
+
+ // 如果要插入的值已经存在了就替换 不然就插进去
+ if ((p = ((TreeBin) f).putTreeVal(hash, key, value)) != null) {
oldVal = p.val;
- if (!onlyIfAbsent)
+ if (!onlyIfAbsent) {
p.val = value;
+ }
}
}
}
}
+ // 红黑树节点数一定不是0
if (binCount != 0) {
// 如果节点数>=8,那么转换链表结构为红黑树结构
- if (binCount >= TREEIFY_THRESHOLD)
- treeifyBin(tab, i);//若length<64,直接tryPresize,两倍table.length;不转红黑树
- if (oldVal != null)
+ if (binCount >= TREEIFY_THRESHOLD) {
+ treeifyBin(tab, i);// 若length<64,直接tryPresize,两倍table.length;不转红黑树
+ }
+ // 如果是替换的 就不增加总数量 直接返回
+ if (oldVal != null) {
return oldVal;
+ }
break;
}
}
@@ -600,10 +647,12 @@ else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
*
* @param m mappings to be stored in this map
*/
+ @Override
public void putAll(Map extends K, ? extends V> m) {
tryPresize(m.size());
- for (Map.Entry extends K, ? extends V> e : m.entrySet())
+ for (Map.Entry extends K, ? extends V> e : m.entrySet()) {
putVal(e.getKey(), e.getValue(), false);
+ }
}
/**
@@ -611,10 +660,12 @@ public void putAll(Map extends K, ? extends V> m) {
* This method does nothing if the key is not in the map.
*
* @param key the key that needs to be removed
+ *
* @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 is null
*/
+ @Override
public V remove(Object key) {
return replaceNode(key, null, null);
}
@@ -629,12 +680,11 @@ final V replaceNode(Object key, V value, Object cv) {
for (Node[] tab = table; ; ) {
Node f;
int n, i, fh;
- if (tab == null || (n = tab.length) == 0 ||
- (f = tabAt(tab, i = (n - 1) & hash)) == null)
+ if (tab == null || (n = tab.length) == 0 || (f = tabAt(tab, i = (n - 1) & hash)) == null) {
break;
- else if ((fh = f.hash) == MOVED)
+ } else if ((fh = f.hash) == MOVED) {
tab = helpTransfer(tab, f);
- else {
+ } else {
V oldVal = null;
boolean validated = false;
synchronized (f) {
@@ -643,40 +693,38 @@ else if ((fh = f.hash) == MOVED)
validated = true;
for (Node e = f, pred = null; ; ) {
K ek;
- if (e.hash == hash &&
- ((ek = e.key) == key ||
- (ek != null && key.equals(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))) {
+ if (cv == null || cv == ev || (ev != null && cv.equals(ev))) {
oldVal = ev;
- if (value != null)
+ if (value != null) {
e.val = value;
- else if (pred != null)
+ } else if (pred != null) {
pred.next = e.next;
- else
+ } else {
setTabAt(tab, i, e.next);
+ }
}
break;
}
pred = e;
- if ((e = e.next) == null)
+ if ((e = e.next) == null) {
break;
+ }
}
} else if (f instanceof TreeBin) {
validated = true;
TreeBin t = (TreeBin) f;
TreeNode r, p;
- if ((r = t.root) != null &&
- (p = r.findTreeNode(hash, key, null)) != null) {
+ 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))) {
+ if (cv == null || cv == pv || (pv != null && cv.equals(pv))) {
oldVal = pv;
- if (value != null)
+ if (value != null) {
p.val = value;
- else if (t.removeTreeNode(p))
+ } else if (t.removeTreeNode(p)) {
setTabAt(tab, i, untreeify(t.first));
+ }
}
}
}
@@ -684,8 +732,9 @@ else if (t.removeTreeNode(p))
}
if (validated) {
if (oldVal != null) {
- if (value == null)
+ if (value == null) {
addCount(-1L, -1);
+ }
return oldVal;
}
break;
@@ -698,6 +747,7 @@ else if (t.removeTreeNode(p))
/**
* Removes all of the mappings from this map.
*/
+ @Override
public void clear() {
long delta = 0L; // negative number of deletions
int i = 0;
@@ -713,9 +763,7 @@ else if ((fh = f.hash) == MOVED) {
} else {
synchronized (f) {
if (tabAt(tab, i) == f) {
- Node p = (fh >= 0 ? f :
- (f instanceof TreeBin) ?
- ((TreeBin) f).first : null);
+ Node p = (fh >= 0 ? f : (f instanceof TreeBin) ? ((TreeBin) f).first : null);
while (p != null) {
--delta;
p = p.next;
@@ -725,8 +773,9 @@ else if ((fh = f.hash) == MOVED) {
}
}
}
- if (delta != 0L)
+ if (delta != 0L) {
addCount(delta, -1);
+ }
}
/**
@@ -747,6 +796,7 @@ else if ((fh = f.hash) == MOVED) {
*
* @return the set view
*/
+ @Override
public KeySetView keySet() {
KeySetView ks;
return (ks = keySet) != null ? ks : (keySet = new KeySetView(this, null));
@@ -770,6 +820,7 @@ public KeySetView keySet() {
*
* @return the collection view
*/
+ @Override
public Collection values() {
ValuesView vs;
return (vs = values) != null ? vs : (values = new ValuesView(this));
@@ -792,6 +843,7 @@ public Collection values() {
*
* @return the set view
*/
+ @Override
public Set> entrySet() {
EntrySetView es;
return (es = entrySet) != null ? es : (entrySet = new EntrySetView(this));
@@ -804,6 +856,7 @@ public Set> entrySet() {
*
* @return the hash code value for this map
*/
+ @Override
public int hashCode() {
int h = 0;
Node[] t;
@@ -826,6 +879,7 @@ public int hashCode() {
*
* @return a string representation of this map
*/
+ @Override
public String toString() {
Node[] t;
int f = (t = table) == null ? 0 : t.length;
@@ -856,12 +910,15 @@ public String toString() {
* of this method.
*
* @param o object to be compared for equality with this map
+ *
* @return {@code true} if the specified object is equal to this map
*/
+ @Override
public boolean equals(Object o) {
if (o != this) {
- if (!(o instanceof Map))
+ if (!(o instanceof Map)) {
return false;
+ }
Map, ?> m = (Map, ?>) o;
Node[] t;
int f = (t = table) == null ? 0 : t.length;
@@ -869,15 +926,14 @@ public boolean equals(Object o) {
for (Node p; (p = it.advance()) != null; ) {
V val = p.val;
Object v = m.get(p.key);
- if (v == null || (v != val && !v.equals(val)))
+ if (v == null || (v != val && !v.equals(val))) {
return false;
+ }
}
for (Map.Entry, ?> e : m.entrySet()) {
Object mk, mv, v;
- if ((mk = e.getKey()) == null ||
- (mv = e.getValue()) == null ||
- (v = get(mk)) == null ||
- (mv != v && !mv.equals(v)))
+ if ((mk = e.getKey()) == null || (mv = e.getValue()) == null || (v = get(
+ mk)) == null || (mv != v && !mv.equals(v)))
return false;
}
}
@@ -889,7 +945,9 @@ public boolean equals(Object o) {
* declared for the sake of serialization compatibility
*/
static class Segment extends ReentrantLock implements Serializable {
+
private static final long serialVersionUID = 2249069246763182397L;
+
final float loadFactor;
Segment(float lf) {
@@ -902,13 +960,13 @@ static class Segment extends ReentrantLock implements Serializable {
* stream (i.e., serializes it).
*
* @param s the stream
+ *
* @throws java.io.IOException if an I/O error occurs
* @serialData the key (Object) and value (Object)
* for each key-value mapping, followed by a null pair.
* The key-value mappings are emitted in no particular order.
*/
- private void writeObject(java.io.ObjectOutputStream s)
- throws java.io.IOException {
+ private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException {
// For serialization compatibility
// Emulate segment calculation from previous version of this class
int sshift = 0;
@@ -920,8 +978,7 @@ private void writeObject(java.io.ObjectOutputStream s)
int segmentShift = 32 - sshift;
int segmentMask = ssize - 1;
@SuppressWarnings("unchecked")
- Segment[] segments = (Segment[])
- new Segment, ?>[DEFAULT_CONCURRENCY_LEVEL];
+ Segment[] segments = (Segment[]) new Segment, ?>[DEFAULT_CONCURRENCY_LEVEL];
for (int i = 0; i < segments.length; ++i)
segments[i] = new Segment(LOAD_FACTOR);
s.putFields().put("segments", segments);
@@ -946,12 +1003,12 @@ private void writeObject(java.io.ObjectOutputStream s)
* Reconstitutes the instance from a stream (that is, deserializes it).
*
* @param s the stream
+ *
* @throws ClassNotFoundException if the class of a serialized object
* could not be found
* @throws java.io.IOException if an I/O error occurs
*/
- private void readObject(java.io.ObjectInputStream s)
- throws java.io.IOException, ClassNotFoundException {
+ private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException {
/*
* To improve performance in typical cases, we create nodes
* while reading, then place in table once size is known.
@@ -974,13 +1031,13 @@ private void readObject(java.io.ObjectInputStream s)
} else
break;
}
- if (size == 0L)
+ if (size == 0L) {
sizeCtl = 0;
- else {
+ } else {
int n;
- if (size >= (long) (MAXIMUM_CAPACITY >>> 1))
+ if (size >= (long) (MAXIMUM_CAPACITY >>> 1)) {
n = MAXIMUM_CAPACITY;
- else {
+ } else {
int sz = (int) size;
n = tableSizeFor(sz + (sz >>> 1) + 1);
}
@@ -992,14 +1049,15 @@ private void readObject(java.io.ObjectInputStream s)
boolean insertAtFront;
Node next = p.next, first;
int h = p.hash, j = h & mask;
- if ((first = tabAt(tab, j)) == null)
+ if ((first = tabAt(tab, j)) == null) {
insertAtFront = true;
- else {
+ } else {
K k = p.key;
if (first.hash < 0) {
TreeBin t = (TreeBin) first;
- if (t.putTreeVal(h, k, p.val) == null)
+ if (t.putTreeVal(h, k, p.val) == null) {
++added;
+ }
insertAtFront = false;
} else {
int binCount = 0;
@@ -1007,9 +1065,7 @@ private void readObject(java.io.ObjectInputStream s)
Node q;
K qk;
for (q = first; q != null; q = q.next) {
- if (q.hash == h &&
- ((qk = q.key) == k ||
- (qk != null && k.equals(qk)))) {
+ if (q.hash == h && ((qk = q.key) == k || (qk != null && k.equals(qk)))) {
insertAtFront = false;
break;
}
@@ -1021,12 +1077,12 @@ private void readObject(java.io.ObjectInputStream s)
p.next = first;
TreeNode hd = null, tl = null;
for (q = p; q != null; q = q.next) {
- TreeNode t = new TreeNode
- (q.hash, q.key, q.val, null, null);
- if ((t.prev = tl) == null)
+ TreeNode t = new TreeNode(q.hash, q.key, q.val, null, null);
+ if ((t.prev = tl) == null) {
hd = t;
- else
+ } else {
tl.next = t;
+ }
tl = t;
}
setTabAt(tab, j, new TreeBin(hd));
@@ -1055,6 +1111,7 @@ private void readObject(java.io.ObjectInputStream s)
* or {@code null} if there was no mapping for the key
* @throws NullPointerException if the specified key or value is null
*/
+ @Override
public V putIfAbsent(K key, V value) {
return putVal(key, value, true);
}
@@ -1064,9 +1121,11 @@ public V putIfAbsent(K key, V value) {
*
* @throws NullPointerException if the specified key is null
*/
+ @Override
public boolean remove(Object key, Object value) {
- if (key == null)
+ if (key == null) {
throw new NullPointerException();
+ }
return value != null && replaceNode(key, null, value) != null;
}
@@ -1075,9 +1134,11 @@ public boolean remove(Object key, Object value) {
*
* @throws NullPointerException if any of the arguments are null
*/
+ @Override
public boolean replace(K key, V oldValue, V newValue) {
- if (key == null || oldValue == null || newValue == null)
+ if (key == null || oldValue == null || newValue == null) {
throw new NullPointerException();
+ }
return replaceNode(key, newValue, oldValue) != null;
}
@@ -1088,9 +1149,11 @@ public boolean replace(K key, V oldValue, V newValue) {
* or {@code null} if there was no mapping for the key
* @throws NullPointerException if the specified key or value is null
*/
+ @Override
public V replace(K key, V value) {
- if (key == null || value == null)
+ if (key == null || value == null) {
throw new NullPointerException();
+ }
return replaceNode(key, value, null);
}
@@ -1104,16 +1167,20 @@ public V replace(K key, V value) {
* @param key the key whose associated value is to be returned
* @param defaultValue the value to return if this map contains
* no mapping for the given key
+ *
* @return the mapping for the key, if present; else the default value
* @throws NullPointerException if the specified key is null
*/
+ @Override
public V getOrDefault(Object key, V defaultValue) {
V v;
return (v = get(key)) == null ? defaultValue : v;
}
+ @Override
public void forEach(BiConsumer super K, ? super V> action) {
- if (action == null) throw new NullPointerException();
+ if (action == null)
+ throw new NullPointerException();
Node[] t;
if ((t = table) != null) {
Traverser it = new Traverser(t, t.length, 0, t.length);
@@ -1124,7 +1191,8 @@ public void forEach(BiConsumer super K, ? super V> action) {
}
public void replaceAll(BiFunction super K, ? super V, ? extends V> function) {
- if (function == null) throw new NullPointerException();
+ if (function == null)
+ throw new NullPointerException();
Node[] t;
if ((t = table) != null) {
Traverser it = new Traverser(t, t.length, 0, t.length);
@@ -1134,8 +1202,7 @@ public void replaceAll(BiFunction super K, ? super V, ? extends V> function) {
V newValue = function.apply(key, oldValue);
if (newValue == null)
throw new NullPointerException();
- if (replaceNode(key, newValue, oldValue) != null ||
- (oldValue = get(key)) == null)
+ if (replaceNode(key, newValue, oldValue) != null || (oldValue = get(key)) == null)
break;
}
}
@@ -1154,6 +1221,7 @@ public void replaceAll(BiFunction super K, ? super V, ? extends V> function) {
*
* @param key key with which the specified value is to be associated
* @param mappingFunction the function to compute a value
+ *
* @return the current (existing or computed) value associated with
* the specified key, or null if the computed value is null
* @throws NullPointerException if the specified key or mappingFunction
@@ -1202,9 +1270,7 @@ else if ((f = tabAt(tab, i = (n - 1) & h)) == null) {
for (Node e = f; ; ++binCount) {
K ek;
V ev;
- if (e.hash == h &&
- ((ek = e.key) == key ||
- (ek != null && key.equals(ek)))) {
+ if (e.hash == h && ((ek = e.key) == key || (ek != null && key.equals(ek)))) {
val = e.val;
break;
}
@@ -1221,8 +1287,7 @@ else if ((f = tabAt(tab, i = (n - 1) & h)) == null) {
binCount = 2;
TreeBin t = (TreeBin) f;
TreeNode r, p;
- if ((r = t.root) != null &&
- (p = r.findTreeNode(h, key, null)) != null)
+ if ((r = t.root) != null && (p = r.findTreeNode(h, key, null)) != null)
val = p.val;
else if ((val = mappingFunction.apply(key)) != null) {
added = true;
@@ -1256,6 +1321,7 @@ else if ((val = mappingFunction.apply(key)) != null) {
*
* @param key key with which a value may be associated
* @param remappingFunction the function to compute a value
+ *
* @return the new value associated with the specified key, or null if none
* @throws NullPointerException if the specified key or remappingFunction
* is null
@@ -1288,9 +1354,7 @@ else if ((fh = f.hash) == MOVED)
binCount = 1;
for (Node e = f, pred = null; ; ++binCount) {
K ek;
- if (e.hash == h &&
- ((ek = e.key) == key ||
- (ek != null && key.equals(ek)))) {
+ if (e.hash == h && ((ek = e.key) == key || (ek != null && key.equals(ek)))) {
val = remappingFunction.apply(key, e.val);
if (val != null)
e.val = val;
@@ -1312,15 +1376,15 @@ else if ((fh = f.hash) == MOVED)
binCount = 2;
TreeBin t = (TreeBin) f;
TreeNode r, p;
- if ((r = t.root) != null &&
- (p = r.findTreeNode(h, key, null)) != null) {
+ if ((r = t.root) != null && (p = r.findTreeNode(h, key, null)) != null) {
val = remappingFunction.apply(key, p.val);
if (val != null)
p.val = val;
else {
delta = -1;
- if (t.removeTreeNode(p))
+ if (t.removeTreeNode(p)) {
setTabAt(tab, i, untreeify(t.first));
+ }
}
}
}
@@ -1346,6 +1410,7 @@ else if ((fh = f.hash) == MOVED)
*
* @param key key with which the specified value is to be associated
* @param remappingFunction the function to compute a value
+ *
* @return the new value associated with the specified key, or null if none
* @throws NullPointerException if the specified key or remappingFunction
* is null
@@ -1355,8 +1420,7 @@ else if ((fh = f.hash) == MOVED)
* @throws RuntimeException or Error if the remappingFunction does so,
* in which case the mapping is unchanged
*/
- public V compute(K key,
- BiFunction super K, ? super V, ? extends V> remappingFunction) {
+ public V compute(K key, BiFunction super K, ? super V, ? extends V> remappingFunction) {
if (key == null || remappingFunction == null)
throw new NullPointerException();
int h = spread(key.hashCode());
@@ -1395,9 +1459,7 @@ else if ((f = tabAt(tab, i = (n - 1) & h)) == null) {
binCount = 1;
for (Node e = f, pred = null; ; ++binCount) {
K ek;
- if (e.hash == h &&
- ((ek = e.key) == key ||
- (ek != null && key.equals(ek)))) {
+ if (e.hash == h && ((ek = e.key) == key || (ek != null && key.equals(ek)))) {
val = remappingFunction.apply(key, e.val);
if (val != null)
e.val = val;
@@ -1416,8 +1478,7 @@ else if ((f = tabAt(tab, i = (n - 1) & h)) == null) {
val = remappingFunction.apply(key, null);
if (val != null) {
delta = 1;
- pred.next =
- new Node(h, key, val, null);
+ pred.next = new Node(h, key, val, null);
}
break;
}
@@ -1473,6 +1534,7 @@ else if ((f = tabAt(tab, i = (n - 1) & h)) == null) {
* @param key key with which the specified value is to be associated
* @param value the value to use if absent
* @param remappingFunction the function to recompute a value if present
+ *
* @return the new value associated with the specified key, or null if none
* @throws NullPointerException if the specified key or the
* remappingFunction is null
@@ -1506,9 +1568,7 @@ else if ((f = tabAt(tab, i = (n - 1) & h)) == null) {
binCount = 1;
for (Node e = f, pred = null; ; ++binCount) {
K ek;
- if (e.hash == h &&
- ((ek = e.key) == key ||
- (ek != null && key.equals(ek)))) {
+ if (e.hash == h && ((ek = e.key) == key || (ek != null && key.equals(ek)))) {
val = remappingFunction.apply(e.val, value);
if (val != null)
e.val = val;
@@ -1526,8 +1586,7 @@ else if ((f = tabAt(tab, i = (n - 1) & h)) == null) {
if ((e = e.next) == null) {
delta = 1;
val = value;
- pred.next =
- new Node(h, key, val, null);
+ pred.next = new Node(h, key, val, null);
break;
}
}
@@ -1535,10 +1594,8 @@ else if ((f = tabAt(tab, i = (n - 1) & h)) == null) {
binCount = 2;
TreeBin t = (TreeBin) f;
TreeNode r = t.root;
- TreeNode p = (r == null) ? null :
- r.findTreeNode(h, key, null);
- val = (p == null) ? value :
- remappingFunction.apply(p.val, value);
+ TreeNode p = (r == null) ? null : r.findTreeNode(h, key, null);
+ val = (p == null) ? value : remappingFunction.apply(p.val, value);
if (val != null) {
if (p != null)
p.val = val;
@@ -1577,6 +1634,7 @@ else if ((f = tabAt(tab, i = (n - 1) & h)) == null) {
* Java Collections framework.
*
* @param value a value to search for
+ *
* @return {@code true} if and only if some key maps to the
* {@code value} argument in this table as
* determined by the {@code equals} method;
@@ -1633,12 +1691,12 @@ public long mappingCount() {
* from the given type to {@code Boolean.TRUE}.
*
* @param the element type of the returned set
+ *
* @return the new set
* @since 1.8
*/
public static KeySetView newKeySet() {
- return new KeySetView
- (new ConcurrentHashMap(), Boolean.TRUE);
+ return new KeySetView(new ConcurrentHashMap(), Boolean.TRUE);
}
/**
@@ -1648,14 +1706,14 @@ public static KeySetView newKeySet() {
* @param initialCapacity The implementation performs internal
* sizing to accommodate this many elements.
* @param the element type of the returned set
+ *
* @return the new set
* @throws IllegalArgumentException if the initial capacity of
* elements is negative
* @since 1.8
*/
public static KeySetView newKeySet(int initialCapacity) {
- return new KeySetView
- (new ConcurrentHashMap(initialCapacity), Boolean.TRUE);
+ return new KeySetView(new ConcurrentHashMap(initialCapacity), Boolean.TRUE);
}
/**
@@ -1666,6 +1724,7 @@ public static KeySetView newKeySet(int initialCapacity) {
* the same value for all additions from this view.
*
* @param mappedValue the mapped value to use for any additions
+ *
* @return the set view
* @throws NullPointerException if the mappedValue is null
*/
@@ -1681,6 +1740,7 @@ public KeySetView keySet(V mappedValue) {
* A node inserted at head of bins during transfer operations.
*/
static final class ForwardingNode extends Node {
+
final Node[] nextTable;
ForwardingNode(Node[] tab) {
@@ -1688,21 +1748,21 @@ static final class ForwardingNode extends Node {
this.nextTable = tab;
}
+ @Override
Node find(int h, Object k) {
// loop to avoid arbitrarily deep recursion on forwarding nodes
outer:
for (Node[] tab = nextTable; ; ) {
Node e;
int n;
- if (k == null || tab == null || (n = tab.length) == 0 ||
- (e = tabAt(tab, (n - 1) & h)) == null)
+ if (k == null || tab == null || (n = tab.length) == 0 || (e = tabAt(tab, (n - 1) & h)) == null)
return null;
for (; ; ) {
int eh;
K ek;
- if ((eh = e.hash) == h &&
- ((ek = e.key) == k || (ek != null && k.equals(ek))))
+ if ((eh = e.hash) == h && ((ek = e.key) == k || (ek != null && k.equals(ek)))) {
return e;
+ }
if (eh < 0) {
if (e instanceof ForwardingNode) {
tab = ((ForwardingNode) e).nextTable;
@@ -1721,10 +1781,12 @@ Node find(int h, Object k) {
* A place-holder node used in computeIfAbsent and compute
*/
static final class ReservationNode extends Node {
+
ReservationNode() {
super(RESERVED, null, null, null);
}
+ @Override
Node find(int h, Object k) {
return null;
}
@@ -1734,31 +1796,47 @@ Node find(int h, Object k) {
/**
* Returns the stamp bits for resizing a table of size n.
- * Must be negative when shifted left by RESIZE_STAMP_SHIFT.
+ * Must be negative负数 when shifted(移位) left by RESIZE_STAMP_SHIFT.
*/
static final int resizeStamp(int n) {
+ // (1 << (RESIZE_STAMP_BITS - 1)) -> 1000 0000 0000 0000
+ // n表示老数组的长度 如果入参length是16
+ // 如果n是16 则是 0001 1011|1000 0000 0000 10000
+ // 结果是 0000 0000 0000 0000 1000 0000 0001 1011
return Integer.numberOfLeadingZeros(n) | (1 << (RESIZE_STAMP_BITS - 1));
}
/**
- * Initializes table, using the size recorded in sizeCtl.
+ * 初始hash表, using the size recorded in sizeCtl.
*/
private final Node[] initTable() {
+ // 数组的临时变量
Node[] tab;
+ // 尺寸控制器临时变量
int sc;
+ // 初始化不成功就一直搞
while ((tab = table) == null || tab.length == 0) {
- if ((sc = sizeCtl) < 0)
+ // 负数代表正在扩容
+ if ((sc = sizeCtl) < 0) {
+ // 此线程不去竞争 只做自旋
Thread.yield(); // lost initialization race; just spin
- else if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) {
+ } else if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) {// 对象 老值 副本 期望值 自旋修改sc
+ // 如果自旋成功返回true会往下走 否则回while处
try {
+ // 按理说 能自旋成功的只有一个线程 这里可能是为了double check
if ((tab = table) == null || tab.length == 0) {
+ // 尺寸控制器赋值
int n = (sc > 0) ? sc : DEFAULT_CAPACITY;
+ // 创建节点对象
@SuppressWarnings("unchecked")
Node[] nt = (Node[]) new Node, ?>[n];
+ // 给数组赋值
table = tab = nt;
+ // sc = 0.75 * n 即阈值
sc = n - (n >>> 2);
}
} finally {
+ // sc之前的赋值不会影响sizeCtl 在这里来给sizeCtl赋值
sizeCtl = sc;
}
break;
@@ -1780,39 +1858,36 @@ else if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) {
private final void addCount(long x, int check) {
CounterCell[] as;
long b, s;
- if ((as = counterCells) != null ||
- !U.compareAndSwapLong(this, BASECOUNT, b = baseCount, s = b + x)) {
+ if ((as = counterCells) != null || !U.compareAndSwapLong(this, BASECOUNT, b = baseCount, s = b + x)) {
CounterCell a;
long v;
int m;
boolean uncontended = true;
- if (as == null || (m = as.length - 1) < 0 ||
- (a = as[ThreadLocalRandom.getProbe() & m]) == null ||
- !(uncontended =
- U.compareAndSwapLong(a, CELLVALUE, v = a.value, v + x))) {
+ if (as == null || (m = as.length - 1) < 0 || (a = as[ThreadLocalRandom.getProbe() & m]) == null || !(uncontended = U.compareAndSwapLong(
+ a, CELLVALUE, v = a.value, v + x))) {
fullAddCount(x, uncontended);
return;
}
- if (check <= 1)
+ if (check <= 1) {
return;
+ }
s = sumCount();
}
if (check >= 0) {
Node[] tab, nt;
int n, sc;
- while (s >= (long) (sc = sizeCtl) && (tab = table) != null &&
- (n = tab.length) < MAXIMUM_CAPACITY) {
+ while (s >= (long) (sc = sizeCtl) && (tab = table) != null && (n = tab.length) < MAXIMUM_CAPACITY) {
int rs = resizeStamp(n);
if (sc < 0) {
- if ((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 ||
- sc == rs + MAX_RESIZERS || (nt = nextTable) == null ||
- transferIndex <= 0)
+ 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))
+ }
+ if (U.compareAndSwapInt(this, SIZECTL, sc, sc + 1)) {
transfer(tab, nt);
- } else if (U.compareAndSwapInt(this, SIZECTL, sc,
- (rs << RESIZE_STAMP_SHIFT) + 2))
+ }
+ } else if (U.compareAndSwapInt(this, SIZECTL, sc, (rs << RESIZE_STAMP_SHIFT) + 2)) {
transfer(tab, null);
+ }
s = sumCount();
}
}
@@ -1822,34 +1897,44 @@ private final void addCount(long x, int check) {
* Helps transfer if a resize is in progress.
*/
final Node[] helpTransfer(Node[] tab, Node f) {
+ // 新数组
Node[] nextTab;
int sc;
- if (tab != null && (f instanceof ForwardingNode) &&
- (nextTab = ((ForwardingNode) f).nextTable) != null) {
+ // 如果正在扩容
+ if (tab != null && (f instanceof ForwardingNode) && (nextTab = ((ForwardingNode) f).nextTable) != null) {
+ // 生成一个和扩容有关的扩容戳 扩容戳的最高位1是相对固定的 1左移15位 后面几位表示数组的长度
+ // 如果n是16 rs是 0000 0000 0000 0000 1000 0000 0001 1011
int rs = resizeStamp(tab.length);
- while (nextTab == nextTable && table == tab &&
- (sc = sizeCtl) < 0) {
- if ((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 ||
- sc == rs + MAX_RESIZERS || transferIndex <= 0)
+ // 如果还在扩容则协助扩容
+ // sc = sizeCtl -N 表示有N-1个线程正在进行扩容操作 如果不能协助扩容 扩容又没有完成就一直空转
+ while (nextTab == nextTable && table == tab && (sc = sizeCtl) < 0) {
+ // 高16位代表扩容的标记、低16位代表并行扩容的线程数
+ // 如果(sc >>> RESIZE_STAMP_SHIFT) != rs 则表示扩容已经完成了 因为生成了新的扩容戳 扩容戳与数组的length相关 length变化则戳记变化
+ // sc == rs + MAX_RESIZERS 达到了最大扩容线程数
+ // 这里简单记作 如果扩容完成了就不协助了 我也没太看懂这个表达式
+ if ((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 || sc == rs + MAX_RESIZERS || transferIndex <= 0) {
break;
+ }
+ // 扩容线程数加一
if (U.compareAndSwapInt(this, SIZECTL, sc, sc + 1)) {
+ // 协助扩容 传入老表 和 新表
transfer(tab, nextTab);
break;
}
}
+ // 返回新的数组
return nextTab;
}
return table;
}
/**
- * Tries to presize table to accommodate the given number of elements.
+ * 尝试预扩容表 以容纳给定的元素个数
*
* @param size number of elements (doesn't need to be perfectly accurate)
*/
private final void tryPresize(int size) {
- int c = (size >= (MAXIMUM_CAPACITY >>> 1)) ? MAXIMUM_CAPACITY :
- tableSizeFor(size + (size >>> 1) + 1);
+ int c = (size >= (MAXIMUM_CAPACITY >>> 1)) ? MAXIMUM_CAPACITY : tableSizeFor(size + (size >>> 1) + 1);
int sc;
while ((sc = sizeCtl) >= 0) {
Node[] tab = table;
@@ -1874,14 +1959,11 @@ else if (tab == table) {
int rs = resizeStamp(n);
if (sc < 0) {
Node[] nt;
- if ((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 ||
- sc == rs + MAX_RESIZERS || (nt = nextTable) == null ||
- transferIndex <= 0)
+ 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))
+ } else if (U.compareAndSwapInt(this, SIZECTL, sc, (rs << RESIZE_STAMP_SHIFT) + 2))
transfer(tab, null);
}
}
@@ -1892,125 +1974,197 @@ else if (tab == table) {
* above for explanation.
*/
private final void transfer(Node[] tab, Node[] nextTab) {
+ // 把老表长赋给n 并声明一个int型步长变量
int n = tab.length, stride;
- if ((stride = (NCPU > 1) ? (n >>> 3) / NCPU : n) < MIN_TRANSFER_STRIDE)
+ // 多线程补偿是 老表长除以8再除以CPU核数 8核电脑NCPU=16
+ // 单线程的步长是n
+ if ((stride = (NCPU > 1) ? (n >>> 3) / NCPU : n) < MIN_TRANSFER_STRIDE) {
+ // 步长
stride = MIN_TRANSFER_STRIDE; // subdivide range
+ }
+ // 新表还没创建
if (nextTab == null) { // initiating
try {
+ // 创建新表
@SuppressWarnings("unchecked")
Node[] nt = (Node[]) new Node, ?>[n << 1];
nextTab = nt;
} catch (Throwable ex) { // try to cope with OOME
+ // 捕获 OOM Exception 为啥给这个值?
sizeCtl = Integer.MAX_VALUE;
return;
}
nextTable = nextTab;
+ // 老表长
transferIndex = n;
}
+ // 新表长
int nextn = nextTab.length;
+ // 创建一个hash值是-1的扩容节点
ForwardingNode fwd = new ForwardingNode(nextTab);
+ // 向前为真
boolean advance = true;
+ // 结束为假
boolean finishing = false; // to ensure sweep before committing nextTab
+ //
for (int i = 0, bound = 0; ; ) {
Node f;
int fh;
+ // 如果需要向前
while (advance) {
+ // 下一个下标和边界
int nextIndex, nextBound;
- if (--i >= bound || finishing)
+ // 当前线程到达处理边界就停下来 或者处理完了也停下来
+ if (--i >= bound || finishing) {
advance = false;
+ }
+ // 下一个要处理完的下标小于0也停下来
else if ((nextIndex = transferIndex) <= 0) {
i = -1;
advance = false;
- } else if (U.compareAndSwapInt
- (this, TRANSFERINDEX, nextIndex,
- nextBound = (nextIndex > stride ?
- nextIndex - stride : 0))) {
+ }
+ // CAS修改transferIndex。 进入该if的情况
+ //1.第一次进入循环,分配每个线程处理的桶的区间
+ //2. 不满足上面两个情况,说明当前线程任务已完成,但总扩容任务还没完成,再次分配扩容任务
+ // 四个入参分别是 当前对象 拿到值需要的偏移量 老值 新值
+ // 偏移TRANSFERINDEX拿到transferIndex在堆里面的值和传入的nextIndex比较是不是一样(没被人改过) 一样就替换并且返回true
+ // 简单理解为划分任务区域
+ else if (U.compareAndSwapInt(this, TRANSFERINDEX, nextIndex,
+ nextBound = (nextIndex > stride ? nextIndex - stride : 0))) {
+ //更新桶边界以及当前桶下标
bound = nextBound;
+ // 注意,从i--以及这里的赋值,可以得知扩容是从高位到低位,即逆序处理,而HashMap中是顺序处理的
i = nextIndex - 1;
+ // 任务分配好了,跳出循环处理当前i
advance = false;
}
}
+ // 笔者认为这里只有 i<0 的条件是有意义的,其余两个都无意义,
+ // 因为i能被赋值的最大值是(nextIndex - 1)=(transferIndex -1)<=(n -1 ),因为transferIndex初始值为n,而且transferIndex与i都是只减不增,不可能达到其他两个条件
+ // i<0,只对应上方while循环中的 i=-1 ,不会对应第一个if中的 --i>=bound
+ // 因为bound = nextBound >=0 ,所以要满足if (--i >= bound),--i>=0必须成立,所以 i<0必不可能成立。而若不满足 1、2个if,就会如上文注释所说再次获取扩容任务
if (i < 0 || i >= n || i + n >= nextn) {
int sc;
+ // 总扩容任务完成
if (finishing) {
+ // 置null, 保持nextTable只会在扩容时不为null的特性
nextTable = null;
table = nextTab;
+ // 0.75n n是老表长
sizeCtl = (n << 1) - (n >>> 1);
return;
}
+ // 总扩容任务未完成,但当前线程已完成,CAS减少扩容线程数量
if (U.compareAndSwapInt(this, SIZECTL, sc = sizeCtl, sc - 1)) {
- if ((sc - 2) != resizeStamp(n) << RESIZE_STAMP_SHIFT)
+ // 这里看似迷的操作,其实是一一对应回addCount / TryPresize中把sizeCtl置为负值时的操作:
+ // U.compareAndSwapInt(this, SIZECTL, sc,(rs << RESIZE_STAMP_SHIFT) + 2
+ if ((sc - 2) != resizeStamp(n) << RESIZE_STAMP_SHIFT) {
return;
+ }
+ //能到这个逻辑时,说明没有其他扩容线程了,即当前线程是最后的扩容线程
+ //总扩容已完成,更新finishing,advance设为true是为了能进入上述的while循环,而且不会有影响,因为一定满足if(finnishing) ,会直接跳出循环
finishing = advance = true;
+ //稳如老狗 ,重新检查一遍全部桶
+ //注意:这里不会受到当前线程的bound影响,执行代码顺序就是
+ //1. while (advance) if (--i >= bound || finishing) ,借助这里完成i递减,然后便跳出循环 (妙,膜拜)
+ //2. 下方的if ((fh = f.hash) == MOVED) advance = true;
+ //3. 1、2循环,至 i<0, 进行本if (i < 0) {if (finishing) } ,至此结束。这里也只是对i<0起作用,跟上面说"另两个if无意义"并不冲突
i = n; // recheck before commit
}
- } else if ((f = tabAt(tab, i)) == null)
+ }
+ // 若当前桶为空,直接放一个fwd占位,表示这个插槽已转移完
+ else if ((f = tabAt(tab, i)) == null) {
advance = casTabAt(tab, i, null, fwd);
- else if ((fh = f.hash) == MOVED)
+ }
+ // 当前桶还没处理,加锁进行处理
+ else if ((fh = f.hash) == MOVED) {
advance = true; // already processed
- else {
+ } else {
synchronized (f) {
+ // 再次确认当前 i 位置,确保没被其他线程修改
if (tabAt(tab, i) == f) {
+ // ln、hn,按笔者理解,其实就是lowNode 跟 highNode 缩写
Node ln, hn;
if (fh >= 0) {
+ // 这里的逻辑跟HashMap的扩容一样,不了解的可以看我另一篇博文:https://blog.csdn.net/Unknownfuture/article/details/105181447
int runBit = fh & n;
+ //注意这里的实现
Node lastRun = f;
for (Node p = f.next; p != null; p = p.next) {
int b = p.hash & n;
+ //runBit跟lastRun 只会在 runBit发生变化时进行更改
+ // 这样在runBit都是一样的情况下,只需要指向lastRun就可以结束了,而不需要再连接上lastRun后面那些runBit一样的结点
if (b != runBit) {
runBit = b;
lastRun = p;
}
}
+ //runBit为0,说明最后更新的runBit=0,同时lastRun也应该继续保留在当前位置
if (runBit == 0) {
+ //更新ln、hn,注意hn为null
ln = lastRun;
hn = null;
} else {
hn = lastRun;
ln = null;
}
+ //结束条件是 p != lastRun ,而不是p != null ,原因如上,节省了循环时间
for (Node p = f; p != lastRun; p = p.next) {
int ph = p.hash;
K pk = p.key;
V pv = p.val;
- if ((ph & n) == 0)
+ // 为0,留在本位置,否则应放到高位
+ // 注:循环结束后,会分为两条链表(ln、hn分别为两条链表头结点)
+ // 一条为逆序链表 (顺序指的是按runBit分类,在原数组的位置)
+ // 另一条链表顺序不定,而不是有的资料所说的顺序/逆序链表
+ // 而为逆序链表的那条,就是在循环前为null的那条,比如若hn=null, 那hn就是逆序链表
+ // 原因可以自己画一画,或者看笔者的图
+
+ // 此外,注意这里的实现是复制新的结点,而不是像hashMap中那样直接另指针指向原结点
+ // 笔者的理解:不修改原结点顺序,保证了在扩容期间,get操作也能正常使用且能返回正确结果
+ if ((ph & n) == 0) {
ln = new Node(ph, pk, pv, ln);
- else
+ } else {
hn = new Node(ph, pk, pv, hn);
+ }
}
+ //ln放到原位置,hn放到扩容后的位置 +n ,不多解释
setTabAt(nextTab, i, ln);
setTabAt(nextTab, i + n, hn);
+ //fwd占位
setTabAt(tab, i, fwd);
+ //标记当前桶处理完了,可以往前推进
advance = true;
- } else if (f instanceof TreeBin) {
+ }
+ // 红黑树类型,逻辑差不多,笔者也不是很懂红黑树,就不班门弄斧了
+ else if (f instanceof TreeBin) {
TreeBin t = (TreeBin) f;
TreeNode lo = null, loTail = null;
TreeNode hi = null, hiTail = null;
int lc = 0, hc = 0;
for (Node e = t.first; e != null; e = e.next) {
int h = e.hash;
- TreeNode p = new TreeNode
- (h, e.key, e.val, null, null);
+ TreeNode p = new TreeNode(h, e.key, e.val, null, null);
if ((h & n) == 0) {
- if ((p.prev = loTail) == null)
+ if ((p.prev = loTail) == null) {
lo = p;
- else
+ } else {
loTail.next = p;
+ }
loTail = p;
++lc;
} else {
- if ((p.prev = hiTail) == null)
+ if ((p.prev = hiTail) == null) {
hi = p;
- else
+ } else {
hiTail.next = p;
+ }
hiTail = p;
++hc;
}
}
- ln = (lc <= UNTREEIFY_THRESHOLD) ? untreeify(lo) :
- (hc != 0) ? new TreeBin(lo) : t;
- hn = (hc <= UNTREEIFY_THRESHOLD) ? untreeify(hi) :
- (lc != 0) ? new TreeBin(hi) : t;
+ ln = (lc <= UNTREEIFY_THRESHOLD) ? untreeify(lo) : (hc != 0) ? new TreeBin(lo) : t;
+ hn = (hc <= UNTREEIFY_THRESHOLD) ? untreeify(hi) : (lc != 0) ? new TreeBin(hi) : t;
setTabAt(nextTab, i, ln);
setTabAt(nextTab, i + n, hn);
setTabAt(tab, i, fwd);
@@ -2030,6 +2184,7 @@ else if ((fh = f.hash) == MOVED)
*/
@sun.misc.Contended
static final class CounterCell {
+
volatile long value;
CounterCell(long x) {
@@ -2043,8 +2198,9 @@ final long sumCount() {
long sum = baseCount;
if (as != null) {
for (int i = 0; i < as.length; ++i) {
- if ((a = as[i]) != null)
+ if ((a = as[i]) != null) {
sum += a.value;
+ }
}
}
return sum;
@@ -2068,23 +2224,21 @@ private final void fullAddCount(long x, boolean wasUncontended) {
if ((a = as[(n - 1) & h]) == null) {
if (cellsBusy == 0) { // Try to attach new Cell
CounterCell r = new CounterCell(x); // Optimistic create
- if (cellsBusy == 0 &&
- U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) {
+ if (cellsBusy == 0 && U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) {
boolean created = false;
try { // Recheck under lock
CounterCell[] rs;
int m, j;
- if ((rs = counterCells) != null &&
- (m = rs.length) > 0 &&
- rs[j = (m - 1) & h] == null) {
+ if ((rs = counterCells) != null && (m = rs.length) > 0 && rs[j = (m - 1) & h] == null) {
rs[j] = r;
created = true;
}
} finally {
cellsBusy = 0;
}
- if (created)
+ if (created) {
break;
+ }
continue; // Slot is now non-empty
}
}
@@ -2097,13 +2251,13 @@ else if (counterCells != as || n >= NCPU)
collide = false; // At max size or stale
else if (!collide)
collide = true;
- else if (cellsBusy == 0 &&
- U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) {
+ else if (cellsBusy == 0 && U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) {
try {
if (counterCells == as) {// Expand table unless stale
CounterCell[] rs = new CounterCell[n << 1];
- for (int i = 0; i < n; ++i)
+ for (int i = 0; i < n; ++i) {
rs[i] = as[i];
+ }
counterCells = rs;
}
} finally {
@@ -2113,8 +2267,7 @@ else if (cellsBusy == 0 &&
continue; // Retry with expanded table
}
h = ThreadLocalRandom.advanceProbe(h);
- } else if (cellsBusy == 0 && counterCells == as &&
- U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) {
+ } else if (cellsBusy == 0 && counterCells == as && U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) {
boolean init = false;
try { // Initialize table
if (counterCells == as) {
@@ -2143,20 +2296,20 @@ private final void treeifyBin(Node[] tab, int index) {
Node b;
int n, sc;
if (tab != null) {
- if ((n = tab.length) < MIN_TREEIFY_CAPACITY)
+ if ((n = tab.length) < MIN_TREEIFY_CAPACITY) {
+ // 不到64 先扩容
tryPresize(n << 1);
- else if ((b = tabAt(tab, index)) != null && b.hash >= 0) {
+ } else if ((b = tabAt(tab, index)) != null && b.hash >= 0) {
synchronized (b) {
if (tabAt(tab, index) == b) {
TreeNode hd = null, tl = null;
for (Node e = b; e != null; e = e.next) {
- TreeNode p =
- new TreeNode(e.hash, e.key, e.val,
- null, null);
- if ((p.prev = tl) == null)
+ TreeNode p = new TreeNode(e.hash, e.key, e.val, null, null);
+ if ((p.prev = tl) == null) {
hd = p;
- else
+ } else {
tl.next = p;
+ }
tl = p;
}
setTabAt(tab, index, new TreeBin(hd));
@@ -2173,10 +2326,11 @@ static Node untreeify(Node b) {
Node hd = null, tl = null;
for (Node q = b; q != null; q = q.next) {
Node p = new Node(q.hash, q.key, q.val, null);
- if (tl == null)
+ if (tl == null) {
hd = p;
- else
+ } else {
tl.next = p;
+ }
tl = p;
}
return hd;
@@ -2188,18 +2342,23 @@ static Node untreeify(Node b) {
* Nodes for use in TreeBins
*/
static final class TreeNode extends Node {
+
TreeNode parent; // red-black tree links
+
TreeNode left;
+
TreeNode right;
+
TreeNode prev; // needed to unlink next upon deletion
+
boolean red;
- TreeNode(int hash, K key, V val, Node next,
- TreeNode parent) {
+ TreeNode(int hash, K key, V val, Node next, TreeNode parent) {
super(hash, key, val, next);
this.parent = parent;
}
+ @Override
Node find(int h, Object k) {
return findTreeNode(h, k, null);
}
@@ -2216,24 +2375,24 @@ final TreeNode findTreeNode(int h, Object k, Class> kc) {
K pk;
TreeNode q;
TreeNode