1.7 版本
HashMap
HashMap#put
public V put(K key, V value) {
if (table == EMPTY_TABLE) {
// 如果table表格还没有初始化,则初始化
inflateTable(threshold);
}
if (key == null)
// 如果传入的是null 则存放在 table[0]位置
return putForNullKey(value);
int hash = hash(key);
// 在table的下标
int i = indexFor(hash, table.length);
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
// 如果存在相同的key,直接覆盖并返回
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
// 没有hash冲突则将元素添加到table中
addEntry(hash, key, value, i);
return null;
}
HashMap#addEntry
void addEntry(int hash, K key, V value, int bucketIndex) {
// 如果元素个数超过设定的容量,且当前需要放的位置存在元素则扩容
if ((size >= threshold) && (null != table[bucketIndex])) {
resize(2 * table.length);
hash = (null != key) ? hash(key) : 0;
bucketIndex = indexFor(hash, table.length);
}
// 创建 entry并设置为头节点
createEntry(hash, key, value, bucketIndex);
}
void createEntry(int hash, K key, V value, int bucketIndex) {
Entry<K,V> e = table[bucketIndex];
table[bucketIndex] = new Entry<>(hash, key, value, e);
size++;
}
HashMap#resize 及 HashMap#transfer方法
void resize(int newCapacity) {
Entry[] oldTable = table;
int oldCapacity = oldTable.length;
if (oldCapacity == MAXIMUM_CAPACITY) {
// 如果大于最大值则修改阈值,直接返回
threshold = Integer.MAX_VALUE;
return;
}
Entry[] newTable = new Entry[newCapacity];
// 进行扩容,
transfer(newTable, initHashSeedAsNeeded(newCapacity));
table = newTable;
// 修改下次扩容的阈值
threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1);
}
void transfer(Entry[] newTable, boolean rehash) {
int newCapacity = newTable.length;
for (Entry<K,V> e : table) {
while(null != e) {
Entry<K,V> next = e.next;
if (rehash) {
e.hash = null == e.key ? 0 : hash(e.key);
}
int i = indexFor(e.hash, newCapacity);
// 头插法, 此处会造成多线程迁移形成一个指向环[ A ->B ->A] 导致get的时候无法结束循环
e.next = newTable[i];
newTable[i] = e;
e = next;
}
}
}
ConcurrentHashMap
ConcurrentHashMap#put
// 1.7 版本
public V put(K key, V value) {
// 获取当前需要放置的 segment
Segment<K,V> s;
if (value == null)
throw new NullPointerException();
int hash = hash(key);
// 根据当前hash得到当前数据所在的 segments 中的下标
int j = (hash >>> segmentShift) & segmentMask;
if ((s = (Segment<K,V>)UNSAFE.getObject // nonvolatile; recheck
(segments, (j << SSHIFT) + SBASE)) == null) // in ensureSegment
// 如果当前 segments[j] 的值为null,初始化
s = ensureSegment(j);
return s.put(key, hash, value, false);
}
ensureSegment 初始化方法
private Segment<K,V> ensureSegment(int k) {
final Segment<K,V>[] ss = this.segments;
long u = (k << SSHIFT) + SBASE; // raw offset
Segment<K,V> seg;
// 如果有其他线程初始化就直接返回
if ((seg = (Segment<K,V>)UNSAFE.getObjectVolatile(ss, u)) == null) {
Segment<K,V> proto = ss[0]; // use segment 0 as prototype
int cap = proto.table.length;
float lf = proto.loadFactor;
int threshold = (int)(cap * lf);
// 复制第一个元素的基础数据信息
HashEntry<K,V>[] tab = (HashEntry<K,V>[])new HashEntry[cap];
if ((seg = (Segment<K,V>)UNSAFE.getObjectVolatile(ss, u))
== null) { // recheck
// 初始化
Segment<K,V> s = new Segment<K,V>(lf, threshold, tab);
// 自旋保证只有一个线程执行并设置成功
while ((seg = (Segment<K,V>)UNSAFE.getObjectVolatile(ss, u))
== null) {
// 初始化设置 segments[k] = s
if (UNSAFE.compareAndSwapObject(ss, u, null, seg = s))
break;
}
}
}
return seg;
}
ConcurrentHashMap.Segment#put
final V put(K key, int hash, V value, boolean onlyIfAbsent) {
// 锁的是 整个Segment对象. 保证只有一个线程获取锁成功,其他线程阻塞.
HashEntry<K,V> node = tryLock() ? null :
scanAndLockForPut(key, hash, value);
V oldValue;
try {
HashEntry<K,V>[] tab = table;
// 得到当前所在的下标
int index = (tab.length - 1) & hash;
// 得到当前下标下的元素
HashEntry<K,V> first = entryAt(tab, index);
// 因为会存在hash冲突,所以需要循环列表
for (HashEntry<K,V> e = first;;) {
if (e != null) {
K k;
if ((k = e.key) == key ||
(e.hash == hash && key.equals(k))) {
// 如果当前需要put的数据 key已存在
oldValue = e.value;
// 如果需要覆盖则覆盖原值
if (!onlyIfAbsent) {
e.value = value;
++modCoun