ArrayList、HashMap、ConcurrentHashMap

[toc]

ArrayList

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
package java.util;

import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;


public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
private static final long serialVersionUID = 8683452581122892189L;

// 默认初始容量大小
private static final int DEFAULT_CAPACITY = 10;

// 有参构造函数的空数组会用 EMPTY_ELEMENTDATA 赋值
private static final Object[] EMPTY_ELEMENTDATA = {};

// 用于默认大小空实例的共享空数组实例。
// 无参构造函数用 DEFAULTCAPACITY_EMPTY_ELEMENTDATA 表明空数组只是暂时的
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

// 保存的数据
// 由于扩容机制,elementData 数组的大小往往大于等于实际需要保存的元素个数,为了节约内存,故不使用默认的序列化操作保存整个 elementData,而是在 writeObject()、readObject() 中手动操作实际保存的元素
transient Object[] elementData;

// 实际元素数量
private int size;

// 带初始容量参数的构造函数
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
// 大于 0,创建指定大小的数组
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
// 确定等于 0,创建空数组
this.elementData = EMPTY_ELEMENTDATA;
} else {
// 非法
throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity);
}
}

// 默认无参构造函数,懒惰初始化,先初始化赋值空数组,当添加第一个元素的时候数组容量才扩成默认值 10
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

// 指定集合复制构造
public ArrayList(Collection<? extends E> c) {
// 将指定集合转换为数组
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// 确保 elementData 为 Object 类型数据
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// 数组的长度为 0,用空数组
this.elementData = EMPTY_ELEMENTDATA;
}
}

// 压缩空间,删除 elementData 后的空位置
public void trimToSize() {
modCount++;
if (size < elementData.length) {
elementData = (size == 0) ? EMPTY_ELEMENTDATA : Arrays.copyOf(elementData, size);
}
}

// 确保扩容后至少能容纳 minCapacity 个元素前的准备
public void ensureCapacity(int minCapacity) {
// 第一次扩容时(即此时的 elementData 为懒惰初始化的 DEFAULTCAPACITY_EMPTY_ELEMENTDATA),最少扩 10
int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) ? 0 : DEFAULT_CAPACITY;
// 第一次最少扩到 10
if (minCapacity > minExpand) {
ensureExplicitCapacity(minCapacity);
}
}

// 确保扩容后至少能容纳 minCapacity 个元素
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
// 第一次扩容至容量不小于 10
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}

private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// 判断是否需要扩容
if (minCapacity - elementData.length > 0)
// 开始扩容
grow(minCapacity);
}

// 最大极限
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

// 扩容的核心方法
private void grow(int minCapacity) {
int oldCapacity = elementData.length;
// 最少扩容至至旧容量的 1.5 倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
// 扩容至 1.5 倍仍小于 minCapacity,则将 minCapacity 当作扩容目标,
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
// 如果新容量是否超出了定义的最大容量,直接上猛药,扩容至 Interger.MAX_VALUE
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
elementData = Arrays.copyOf(elementData, newCapacity);
}

// 比较 minCapacity 和 MAX_ARRAY_SIZE
private static int hugeCapacity(int minCapacity) {
// 溢出为负数
if (minCapacity < 0)
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;
}

public int size() {
return size;
}

public boolean isEmpty() {
return size == 0;
}

public boolean contains(Object o) {
return indexOf(o) >= 0;
}

// 正向查找目标首次出现的位置
public int indexOf(Object o) {
// 空元素特殊处理,防止 NPE
if (o == null) {
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
} else {
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
}
// 若没找到,返回 -1
return -1;
}


// 反向查找目标首次出现的位置
public int lastIndexOf(Object o) {
// 空元素特殊处理,防止 NPE
if (o == null) {
for (int i = size-1; i >= 0; i--)
if (elementData[i]==null)
return i;
} else {
for (int i = size-1; i >= 0; i--)
if (o.equals(elementData[i]))
return i;
}
// 若没找到,返回 -1
return -1;
}

// 返回此 ArrayList 实例的拷贝,并拷贝一份 elementData
public Object clone() {
try {
ArrayList<?> v = (ArrayList<?>) super.clone();
v.elementData = Arrays.copyOf(elementData, size);
v.modCount = 0;
return v;
} catch (CloneNotSupportedException e) {
throw new InternalError(e);
}
}

// 顺序返回一个新的包含所有元素的数组
public Object[] toArray() {
return Arrays.copyOf(elementData, size);
}

// 尝试将所有元素放在 a 中返回
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
if (a.length < size)
// 给定的容器数组 a 不够长,返回一个新的和 a 同类型的数组
return (T[]) Arrays.copyOf(elementData, size, a.getClass());
System.arraycopy(elementData, 0, a, 0, size);
if (a.length > size)
a[size] = null;
return a;
}

@SuppressWarnings("unchecked")
E elementData(int index) {
return (E) elementData[index];
}


public E get(int index) {
rangeCheck(index);
return elementData(index);
}

// 替换此列表中指定位置的元素并返回旧元素
public E set(int index, E element) {
rangeCheck(index);
E oldValue = elementData(index);
elementData[index] = element;
return oldValue;
}

// 在尾部添加指定元素
public boolean add(E e) {
// 确保容量足够
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}

// 指定位置插入指定的元素
public void add(int index, E element) {
// 进行界限检查
rangeCheckForAdd(index);
// 确保容量足够
ensureCapacityInternal(size + 1);
// 后移 index 位置之后的元素
System.arraycopy(elementData, index, elementData, index + 1, size - index);
// 在 index 位置插入
elementData[index] = element;
size++;
}

// 删除该列表中指定位置的元素并返回该元素
public E remove(int index) {
rangeCheck(index);
modCount++;
E oldValue = elementData(index);
int numMoved = size - index - 1;
if (numMoved > 0)
// 前移指定位置之后的元素
System.arraycopy(elementData, index + 1, elementData, index, numMoved);
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}

// 指定元素第一次出现时将其删除
public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
// 不包含指定元素
return false;
}

// 不做范围检查以及不返回删除元素的删除方法
private void fastRemove(int index) {
modCount++;
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index, numMoved);
elementData[--size] = null; // clear to let GC do its work
}

// 删除所有元素
public void clear() {
modCount++;
for (int i = 0; i < size; i++)
elementData[i] = null;
size = 0;
}

// 向列表的末尾插入集合的元素
public boolean addAll(Collection<? extends E> c) {
Object[] a = c.toArray();
int numNew = a.length;
// 确保容量
ensureCapacityInternal(size + numNew); // Increments modCount
// 将 a 的元素插入
System.arraycopy(a, 0, elementData, size, numNew);
size += numNew;
return numNew != 0;
}

// 向列表的指定位置批量插入集合的元素
public boolean addAll(int index, Collection<? extends E> c) {
rangeCheckForAdd(index);
Object[] a = c.toArray();
int numNew = a.length;
// 确保容量
ensureCapacityInternal(size + numNew); // Increments modCount
int numMoved = size - index;
if (numMoved > 0)
System.arraycopy(elementData, index, elementData, index + numNew, numMoved);
System.arraycopy(a, 0, elementData, index, numNew);
size += numNew;
return numNew != 0;
}

// 删除从 fromIndex (含)到 toIndex 之间的元素
protected void removeRange(int fromIndex, int toIndex) {
modCount++;
int numMoved = size - toIndex;
System.arraycopy(elementData, toIndex, elementData, fromIndex, numMoved);
// clear to let GC do its work
int newSize = size - (toIndex-fromIndex);
for (int i = newSize; i < size; i++) {
elementData[i] = null;
}
size = newSize;
}

// 检查给定的索引是否在范围内
private void rangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}

private void rangeCheckForAdd(int index) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}

// 返回 IndexOutOfBoundsException 细节信息
private String outOfBoundsMsg(int index) {
return "Index: "+index+", Size: "+size;
}

// 删除指定集合中包含的所有元素
public boolean removeAll(Collection<?> c) {
Objects.requireNonNull(c);
// 如果此列表被修改则返回 true
return batchRemove(c, false);
}

// 删除其中不包含在指定集合中的所有元素
public boolean retainAll(Collection<?> c) {
Objects.requireNonNull(c);
return batchRemove(c, true);
}


/**
* 从列表中的指定位置开始,返回列表中的元素(按正确顺序)的列表迭代器。
* 指定的索引表示初始调用将返回的第一个元素为 next 。 初始调用 previous 将返回指定索引减 1 的元素。
* 返回的列表迭代器是 fail-fast 。
*/
public ListIterator<E> listIterator(int index) {
if (index < 0 || index > size)
throw new IndexOutOfBoundsException("Index: "+index);
return new ListItr(index);
}

/**
* 返回列表中的列表迭代器(按适当的顺序)。
* 返回的列表迭代器是fail-fast 。
*/
public ListIterator<E> listIterator() {
return new ListItr(0);
}

/**
* 以正确的顺序返回该列表中的元素的迭代器。
* 返回的迭代器是 fail-fast 。
*/
public Iterator<E> iterator() {
return new Itr();
}

HashMap

HashMap 通过 key 的 hashCode() 经过扰动函数处理扩散到高位后得到 hash 值,然后通过 (n - 1) & hash 判断当前元素存放的位置),如果当前位置存在元素的话,就判断该元素与要存入的元素的 hash 值以及 key 是否相同,如果相同的话,直接覆盖,不相同就通过拉链法解决冲突。

之所以用 (n - 1) 是因为 n 规定为 2 的整数次幂,n 的二进制表示最低位一定为 0,与 hash 进行按位与操作后最低位仍为 0,这就导致 i 值只能为偶数,浪费了数组中索引为奇数的空间,同时增加了 hash 冲突发生的概率。

计算哈希时之所以要右移 16 位,是因为当数组长度 n 较小时,n-1 的二进制数高 16 位全部为 0,只能利用到 h 的低 16 位数据,提高了 hash 冲突发生的可能性。

1
2
3
4
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

拉链数组长度大于 8 时,调用 treeifyBin()方法,然后根据数组长度是否大于等于 64 ,执行红黑树转换或扩容操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable {
private static final long serialVersionUID = 362498820763181265L;

// 初始容量是16
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;

// 最大容量
static final int MAXIMUM_CAPACITY = 1 << 30;

// 填充因子
static final float DEFAULT_LOAD_FACTOR = 0.75f;

// 当桶(bucket)上的结点数大于此值时调用 treeifyBin() 转化为红黑树或扩容
static final int TREEIFY_THRESHOLD = 8;

// 当桶(bucket)上的结点数小于此值时调用 untreeify()
static final int UNTREEIFY_THRESHOLD = 6;

// table 长度大于等于 64 时,treeifyBin() 中执行红黑树转换操作
static final int MIN_TREEIFY_CAPACITY = 64;

// 存储元素的数组,总是 2 的整数次幂
transient Node<k,v>[] table;

// 存放具体元素的集
transient Set<map.entry<k,v>> entrySet;

// 存放的元素个数
transient int size;

// 每次扩容和更改 map 结构的计数器
transient int modCount;

// 临界值(容量 x 填充因子),当实际大小超过临界值时,会进行扩容
int threshold;

// loadFactor 太大导致查找元素效率低,太小导致数组的利用率低,存放的数据会很分散
final float loadFactor;
}

桶节点定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
V value;
Node<K,V> next;
Node(int hash, K key, V value, Node<K,V> next) {
this.hash = hash;
this.key = key;
this.value = value;
this.next = next;
}
public final K getKey() { return key; }
public final V getValue() { return value; }
public final String toString() { return key + "=" + value; }

// 重写 hashCode() 方法
public final int hashCode() {
return Objects.hashCode(key) ^ Objects.hashCode(value);
}

public final V setValue(V newValue) {
V oldValue = value;
value = newValue;
return oldValue;
}

// 重写 equals()
public final boolean equals(Object o) {
if (o == this)
return true;
if (o instanceof Map.Entry) {
Map.Entry<?,?> e = (Map.Entry<?,?>)o;
// key 与 value 均相同,则判断为相同
if (Objects.equals(key, e.getKey()) &&
Objects.equals(value, e.getValue()))
return true;
}
return false;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
static final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V> {
TreeNode<K,V> parent;
TreeNode<K,V> left;
TreeNode<K,V> right;
TreeNode<K,V> prev;
// 判断颜色
boolean red;
TreeNode(int hash, K key, V val, Node<K,V> next) {
super(hash, key, val, next);
}
// 返回根节点
final TreeNode<K,V> root() {
for (TreeNode<K,V> r = this, p;;) {
if ((p = r.parent) == null)
return r;
r = p;
}
}
}

部分构造函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// 包含另一个 Map 的构造函数
public HashMap(Map<? extends K, ? extends V> m) {
this.loadFactor = DEFAULT_LOAD_FACTOR;
putMapEntries(m, false);
}

final void putMapEntries(Map<? extends K, ? extends V> m, boolean evict) {
int s = m.size();
if (s > 0) {
// 判断 table 是否已经初始化
if (table == null) {
// 未初始化,s 为 m 的实际元素个数
float ft = ((float)s / loadFactor) + 1.0F;
int t = ((ft < (float)MAXIMUM_CAPACITY) ? (int)ft : MAXIMUM_CAPACITY);
// 计算得到的 t 大于阈值,则初始化阈值
if (t > threshold)
threshold = tableSizeFor(t);
}
// 已初始化,并且 m 元素个数大于阈值,进行扩容处理
else if (s > threshold)
resize();
// 将 m 中的所有元素添加至 HashMap 中
for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) {
K key = e.getKey();
V value = e.getValue();
putVal(hash(key), key, value, false, evict);
}
}
}

放入元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64

public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i;
// table 未初始化或者长度为 0,进行扩容
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;
// 计算元素应存放在哪个桶中
if ((p = tab[i = (n - 1) & hash]) == null)
// 桶为空,新生成结点放入桶中(此时,这个结点是放在数组中)
tab[i] = newNode(hash, key, value, null);
else {
// 桶不为空,发生了 hash 冲突
Node<K,V> e; K k;
// 判断桶头部的元素是否与插入的 key 一样,若相同那就直接替换
if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k))))
e = p;
// 在红黑树中插入
else if (p instanceof TreeNode)
// 放入树中
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
// 在链表中插入
else {
for (int binCount = 0; ; ++binCount) {
// 链表中不存在与待插入数据 key 相同的元素
// 到达链表的尾部
if ((e = p.next) == null) {
// 在尾部插入新结点
p.next = newNode(hash, key, value, null);
// 结点数量达到阈值(默认为 8 ),执行 treeifyBin 方法
// 当数组长度大于等于 64 时,转换为红黑树,否则,只是对数组扩容。
if (binCount >= TREEIFY_THRESHOLD - 1) // 8 - 1
treeifyBin(tab, hash);
break;
}
// 链表中存在与待插入数据 key 相同的元素
if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
// 链表中存在与待插入数据 key 相同的元素,则覆盖
if (e != null) {
V oldValue = e.value;
// onlyIfAbsent 为 false(允许覆盖)或者旧值为 null
if (!onlyIfAbsent || oldValue == null)
//用新值替换旧值
e.value = value;
// 访问后回调
afterNodeAccess(e);
// 返回旧值
return oldValue;
}
}
++modCount;
// 实际大小大于阈值则扩容
if (++size > threshold)
resize();
// 插入后回调
afterNodeInsertion(evict);
return null;
}

获取元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public V get(Object key) {
Node<K,V> e;
return (e = getNode(hash(key), key)) == null ? null : e.value;
}

final Node<K,V> getNode(int hash, Object key) {
Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
// 桶中有数据
if ((tab = table) != null && (n = tab.length) > 0 && (first = tab[(n - 1) & hash]) != null) {
// 先在桶中对应位置的头部做一次检查
if (first.hash == hash && ((k = first.key) == key || (key != null && key.equals(k))))
return first;
// 检查桶中对应位置的后面元素
if ((e = first.next) != null) {
// 在树中 get
if (first instanceof TreeNode)
return ((TreeNode<K,V>)first).getTreeNode(hash, key);
// 遍历链表 get
do {
if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k))))
return e;
} while ((e = e.next) != null);
}
}
return null;
}

扩容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
final Node<K,V>[] resize() {
Node<K,V>[] oldTab = table;
int oldCap = (oldTab == null) ? 0 : oldTab.length;
int oldThr = threshold;
int newCap, newThr = 0;
if (oldCap > 0) {
// 超过最大值就不再扩充了,就只好随它碰撞去吧
if (oldCap >= MAXIMUM_CAPACITY) {
threshold = Integer.MAX_VALUE;
return oldTab;
}
// 没超过最大值,就扩充为原来的 2 倍
else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY && oldCap >= DEFAULT_INITIAL_CAPACITY)
newThr = oldThr << 1;
}
else if (oldThr > 0) // initial capacity was placed in threshold
newCap = oldThr;
else {
// signifies using defaults
newCap = DEFAULT_INITIAL_CAPACITY;
newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
}
// 计算新的 resize 上限
if (newThr == 0) {
float ft = (float)newCap * loadFactor;
newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ? (int)ft : Integer.MAX_VALUE);
}
threshold = newThr;
@SuppressWarnings({"rawtypes","unchecked"})
Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
table = newTab;
if (oldTab != null) {
// 把每个 bucket 都移动到新的 buckets 中
for (int j = 0; j < oldCap; ++j) {
Node<K,V> e;
if ((e = oldTab[j]) != null) {
oldTab[j] = null;
if (e.next == null)
newTab[e.hash & (newCap - 1)] = e;
else if (e instanceof TreeNode)
((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
else {
Node<K,V> loHead = null, loTail = null;
Node<K,V> hiHead = null, hiTail = null;
Node<K,V> next;
do {
next = e.next;
// 原索引
if ((e.hash & oldCap) == 0) {
if (loTail == null)
loHead = e;
else
loTail.next = e;
loTail = e;
}
// 原索引 + oldCap
else {
if (hiTail == null)
hiHead = e;
else
hiTail.next = e;
hiTail = e;
}
} while ((e = next) != null);
// 原索引放到 bucket 里
if (loTail != null) {
loTail.next = null;
newTab[j] = loHead;
}
// 原索引 + oldCap 放到 bucket 里
if (hiTail != null) {
hiTail.next = null;
newTab[j + oldCap] = hiHead;
}
}
}
}
}
return newTab;
}

ConcurrentHashMap

传统的 HashMap 在多线程的场景下可能会出现“死链”问题

部分属性和内部类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 默认为 0,初始化时为 -1,扩容时为 -(1 + 扩容线程数),初始化或扩容完成后,为下一次扩容的阈值
private transient volatile int sizeCtl;

// 哈希表的具体实现
static class Node<K,V> implements Map.Entry<K,V> {}

// 哈希表
transient volatile Node<K,V>[] table;

// 扩容时的新哈希表
private transient volatile Node<K,V>[] nextTable;

// 扩容时某个 bin 迁移完毕,则用 ForwardingNode 作为旧 table bin 的头节点用于标识该 bin 已经处理完
static final class ForwardingNode<K,V> extends Node<K,V> {}

// compute() 和 computeIfAbsent() 中用来占位,计算完后替换为普通 Node
static final class ReservationNode<K,V> extends Node<K,V> {}

// treebin 的头节点,保存 root 和 first 信息
static final class TreeBin<K,V> extends Node<K,V> {}

// treebin 的节点,保存 parent、left、right 信息
static final class TreeNode<K,V> extends Node<K,V> {}

对 table 中指定位置的 bin 的头节点进行操作

1
2
3
4
5
static final <K,V> Node<K,V> tabAt(Node<K,V>[] tab, int i) { }

static final <K,V> boolean casTabAt(Node<K,V>[] tab, int i, Node<K,V> c, Node<K,V> v) { }

static final <K,V> void setTabAt(Node<K,V>[] tab, int i, Node<K,V> v) { }

构造器

懒惰初始化

1
2
3
4
5
6
7
8
9
10
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);
// tableSizeFor 仍然是保证计算的大小是 2^n, 即 16,32,64 ...
int cap = (size >= (long)MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : tableSizeFor((int)size);
this.sizeCtl = cap;
}

获取元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public V get(Object key) {
Node<K,V>[] tab; Node<K,V> e, p; int n, eh; K ek;
// spread 方法能确保返回结果是正数,哈希码为负数为特殊标记
int h = spread(key.hashCode());
if ((tab = table) != null && (n = tab.length) > 0 && (e = tabAt(tab, (n - 1) & h)) != null) {
// 如果头结点已经是要查找的 key
if ((eh = e.hash) == h) {
if ((ek = e.key) == key || (ek != null && key.equals(ek)))
return e.val;
}
/*
static final int MOVED = -1; // 用于 Forwarding nodes 表示正在扩容中
static final int TREEBIN = -2; // 用于树的根节点
static final int RESERVED = -3; // hash for transient reservations
static final int HASH_BITS = 0x7fffffff; // usable bits of normal node hash
*/
// hash 为负数表示该 bin 在扩容中或者已经是 treebin, 这时调用 find 方法来查找
else if (eh < 0)
return (p = e.find(h, key)) != null ? p.val : null;
// 正常遍历链表, 用 equals 比较
while ((e = e.next) != null) {
if (e.hash == h &&
((ek = e.key) == key || (ek != null && key.equals(ek))))
return e.val;
}
}
return null;
}

放入元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
public V put(K key, V value) 
return putVal(key, value, false);
}

// onlyIfAbsent 若为 true,表示不会覆盖元素
final V putVal(K key, V value, boolean onlyIfAbsent) {
// ConcurrentHashMap 不允许有空的 key 或 value
if (key == null || value == null) throw new NullPointerException();
// 其中 spread 方法会综合高位低位, 具有更好的 hash 性
int hash = spread(key.hashCode());
int binCount = 0;
for (Node<K,V>[] tab = table;;) {
// f 是链表头节点
// fh 是链表头结点的 hash
// i 是链表在 table 中的下标
Node<K,V> f; int n, i, fh;
// 第一次 put,初始化 table
if (tab == null || (n = tab.length) == 0)
// 用了 cas, 无需 synchronized 创建成功,进入下一轮循环
tab = initTable();
// 未发生哈希冲突,直接添加
else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
// 添加链表头使用了 cas, 无需 synchronized
if (casTabAt(tab, i, null, new Node<K,V>(hash, key, value, null)))
break;
}
// 此时其他线程正在扩容,帮忙扩容
else if ((fh = f.hash) == MOVED)
tab = helpTransfer(tab, f);
else {
V oldVal = null;
// 锁住链表头节点
synchronized (f) {
// 再次确认链表头节点没有被移动
if (tabAt(tab, i) == f) {
// 链表
if (fh >= 0) {
binCount = 1;
// 遍历链表
for (Node<K,V> e = f;; ++binCount) {
K ek;
// 找到相同的 key
if (e.hash == hash && ((ek = e.key) == key || (ek != null && key.equals(ek)))) {
oldVal = e.val;
// 更新
if (!onlyIfAbsent)
e.val = value;
break;
}
Node<K,V> pred = e;
// 已经是最后的节点了, 新增 Node, 追加至链表尾
if ((e = e.next) == null) { value, null);
break;
}
}
}
// 红黑树
else if (f instanceof TreeBin) {
Node<K,V> p;
binCount = 2;
// putTreeVal 会看 key 是否已经在树中, 是, 则返回对应的 TreeNode
if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key, value)) != null) {
oldVal = p.val;
if (!onlyIfAbsent)
p.val = value;
}
}
}
// 释放链表头节点的锁
}

// binCount 大于 0 则表示发生过冲突
if (binCount != 0) {
if (binCount >= TREEIFY_THRESHOLD)
// 如果链表长度 >= 树化阈值(8), 进行链表转为红黑树
treeifyBin(tab, i);
if (oldVal != null)
return oldVal;
break;
}
}
}
// 增加 size 计数
addCount(1L, binCount);
return null;
}

private final Node<K,V>[] initTable() {
Node<K,V>[] tab; int sc;
while ((tab = table) == null || tab.length == 0) {
if ((sc = sizeCtl) < 0)
Thread.yield();
// 尝试将 sizeCtl 设置为 -1(表示初始化 table)
else if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) {
// 获得锁, 创建 table, 这时其它线程会在 while() 循环中 yield 直至 table 创建
try {
if ((tab = table) == null || tab.length == 0) {
int n = (sc > 0) ? sc : DEFAULT_CAPACITY;
Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n];
table = tab = nt;
sc = n - (n >>> 2);
}
} finally
sizeCtl = sc;
}
break;
}
}
return tab;
}

// 用到 LongAdder 的思想,设置多个累加单元,如果超过阈值,则进行扩容
private final void addCount(long x, int check) {
CounterCell[] as; long b, s;
if (
// 已经有了 counterCells, 向 cell 累加
(as = counterCells) != null ||
// 还没有, 向 baseCount 累加
!U.compareAndSwapLong(this, BASECOUNT, b = baseCount, s = b + x)
) {
CounterCell a; long v; int m;
boolean uncontended = true;
if (
// 还没有 counterCells
as == null || (m = as.length - 1) < 0 ||
// 还没有 cell
(a = as[ThreadLocalRandom.getProbe() & m]) == null ||
// cell cas 增加计数失败
!(uncontended = U.compareAndSwapLong(a, CELLVALUE, v = a.value, v + x))
) {
// 创建累加单元数组和cell, 累加重试
fullAddCount(x, uncontended);
return;
}
if (check <= 1)
return;
// 获取元素个数
s = sumCount();
}
if (check >= 0) {
Node<K,V>[] tab, nt; int n, sc;
// 大于扩容阈值 sizeCtl 则进行扩容
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)
break;
// newtable 已经创建了,帮忙扩容
if (U.compareAndSwapInt(this, SIZECTL, sc, sc + 1))
transfer(tab, nt);
}
// 需要扩容,将 SIZECTL 置为负数
else if (U.compareAndSwapInt(this, SIZECTL, sc, (rs << RESIZE_STAMP_SHIFT) + 2))
// 懒惰初始化
transfer(tab, null);
s = sumCount();
}
}
}

红黑树

红黑树的本质是:定义一系列规则,可在 O(logN) 内完成查找、增加、删除等操作的自平衡二叉搜索树。规则如下:

  1. 节点是红色或黑色;
  2. 自上而下的路径上不能有两个连续的红色节点;
  3. 从任一节点到其每个叶子的所有简单路径都包含相同数目的黑色节点;
  4. 所有空节点看作黑色节点;
  5. 根节点是黑色(可由2、3推出)。

其中,第2、3条可保证任意节点到其每个叶子节点路径最长不会超过最短路径的2倍

插入

新插入的节点默认为红色。有四种情况:

1、插入的节点无父节点,即插入的节点为根节点

2、插入的节点父亲为黑色

3、插入的节点父亲为红色且叔叔为红色

2、插入的节点父亲为黑色且叔叔为黑色

case 1: 插入的节点为根节点

直接将红色变为黑色

eg:插入 9

红色的 9 变成黑色

case 2: 插入的节点的父亲为黑色

没有破坏规则,无需调整

eg:插入 4

case 3: 插入的节点的父亲为红色且叔叔为红色

父亲和叔叔全变黑,祖父变红并看作新加入的红色节点递归处理

eg:插入 1

红色的 2 和 4 变黑,3 变红,看作新加入的节点

红色的 3 看作新加入的节点,此时为 case 3 ”插入的节点 3 的父亲 5 和叔叔 13 为红色“,将 5 和 13 变黑,9 变红

红色的 9 看作新加入的节点,此时为 case 1 ”插入的节点为根节点“,直接将红色的 9 变黑

case 4: 插入的节点的父亲为红色且叔叔为黑色

  • 左左(插入节点和它的父节点都为左孩子):父亲变黑,祖父变红,将祖父节点为根节点的子树右旋

eg: 插入 2

将 3 变黑,5 变红

将 5 为根节点的子树右旋

  • 左右(它的父节点为左孩子、插入节点为右孩子):以插入节点的父节点为根节点的子树进行左旋,变为左左后将插入节点的父节点看作插入节点处理

eg:插入 4

将 3 为根节点的子树左旋

此时为 case 4 的左左情况,将 3 看作插入节点,则将 4 变黑,5 变红

将 5 为根节点的子树右旋

  • 右右(插入节点和它的父节点都为右孩子):父亲变黑,祖父变红,将祖父节点为根节点的子树左旋
  • 右左(它的父节点为右孩子、插入节点为左孩子):以插入节点的父节点为根节点的子树进行右旋,变为右右后将插入节点的父节点看作插入节点处理

删除

有四种情况:

0、删除的节点有两个孩子节点,转化为没有孩子或只有一个孩子节点

1、删除的节点无父节点,即插入的节点为根节点

2、删除的节点为黑色,剩下的为红色

3、插入的节点父亲为红色且叔叔为红色

2、插入的节点父亲为黑色且叔叔为黑色