# 通过源码分析工作原理

transient HashMapEntry<K, V>[] table;

public HashMap(int capacity) {
if (capacity < 0) {
throw new IllegalArgumentException("Capacity: " + capacity);
}

if (capacity == 0) {
@SuppressWarnings("unchecked")
HashMapEntry<K, V>[] tab = (HashMapEntry<K, V>[]) EMPTY_TABLE;
table = tab;
threshold = -1; // Forces first put() to replace EMPTY_TABLE
return;
}

if (capacity < MINIMUM_CAPACITY) {
capacity = MINIMUM_CAPACITY;
} else if (capacity > MAXIMUM_CAPACITY) {
capacity = MAXIMUM_CAPACITY;
} else {
capacity = Collections.roundUpToPowerOfTwo(capacity);
}
makeTable(capacity);
}

HashMap里有一个数组table，它存储的元素类型是HashMapEntry，后面会介绍；capacity指的就是这个数组的长度。如果指定数组长度为0，会抛出异常；如果为0，会将table指向EMPTY_TABLE，这个EMPTY_TABLE实际就是长度为2的数组（MINIMUM_CAPACITY 右移1位）：

private static final int MINIMUM_CAPACITY = 4;
private static final int MAXIMUM_CAPACITY = 1 << 30;

private static final Entry[] EMPTY_TABLE = new HashMapEntry[MINIMUM_CAPACITY >>> 1];

/**
* The table is rehashed when its size exceeds this threshold.
* The value of this field is generally .75 * capacity, except when
* the capacity is zero, as described in the EMPTY_TABLE declaration
* above.
*/
private transient int threshold;

private HashMapEntry<K, V>[] makeTable(int newCapacity) {
@SuppressWarnings("unchecked") HashMapEntry<K, V>[] newTable
= (HashMapEntry<K, V>[]) new HashMapEntry[newCapacity];
table = newTable;
threshold = (newCapacity >> 1) + (newCapacity >> 2); // 3/4 capacity
return newTable;
}

static class HashMapEntry<K, V> implements Entry<K, V> {
final K key;
V value;
final int hash;
HashMapEntry<K, V> next;

HashMapEntry(K key, V value, int hash, HashMapEntry<K, V> next) {
this.key = key;
this.value = value;
this.hash = hash;
this.next = next;
}

@Override public final boolean equals(Object o) {
if (!(o instanceof Entry)) {
return false;
}
Entry<?, ?> e = (Entry<?, ?>) o;
return Objects.equal(e.getKey(), key)
&& Objects.equal(e.getValue(), value);
}

@Override public final int hashCode() {
return (key == null ? 0 : key.hashCode()) ^
(value == null ? 0 : value.hashCode());
}
}

@Override
public V put(K key, V value) {
if (key == null) {
return putValueForNullKey(value);
}

int hash = Collections.secondaryHash(key);
HashMapEntry<K, V>[] tab = table;
int index = hash & (tab.length - 1);
for (HashMapEntry<K, V> e = tab[index]; e != null; e = e.next) {
if (e.hash == hash && key.equals(e.key)) {
preModify(e);
V oldValue = e.value;
e.value = value;
return oldValue;
}
}

// No entry for (non-null) key is present; create one
modCount++;
if (size++ > threshold) {
tab = doubleCapacity();
index = hash & (tab.length - 1);
}
return null;
}

transient HashMapEntry<K, V> entryForNullKey;

private V putValueForNullKey(V value) {
HashMapEntry<K, V> entry = entryForNullKey;
if (entry == null) {
size++;
modCount++;
return null;
} else {
preModify(entry);
V oldValue = entry.value;
entry.value = value;
return oldValue;
}
}

int index = hash & (tab.length - 1);

void addNewEntry(K key, V value, int hash, int index) {
table[index] = new HashMapEntry<K, V>(key, value, hash, table[index]);
}

# 总结

HashMap的数据结构基于数组和链表。用数组存储HashMapEntry元素，当调用put方法去存储数据时，对key调用hashCode()并可能再做进一步加工，得到一个hash值，通过hash值可以找到bucket的位置，如果bucket位置已经有其他元素了（即hash值相同），那么就通过链表结构把hash相同的元素放到链表的下一个节点；当调用get方法去获取数据时，找到bucket以后，会通过key的equals方法在链表中找到目标元素。这里需要注意hashCode()和equals()方法的区别，它们均需保证计算得到的值在插入HashMap后不会发生改变；并需尽可能保证两个不同元素的hashCode方法返回值不同，这样碰撞的几率会小，从而提高HashMap的性能；

# 多线程并发问题

### 多线程put时可能导致元素丢失

addNewEntry时，调用table[index] = new HashMapEntry< K, V >(key, value, hash, table[index]);

### Rehash时可能出现环链导致死循环

Rehash时，元素存储位置可能发生更换，代码如下：

for (int j = 0; j < oldCapacity; j++) {
/*
* Rehash the bucket using the minimum number of field writes.
* This is the most subtle and delicate code in the class.
*/
HashMapEntry<K, V> e = oldTable[j];
if (e == null) {
continue;
}
int highBit = e.hash & oldCapacity;
HashMapEntry<K, V> broken = null;
newTable[j | highBit] = e;
for (HashMapEntry<K, V> n = e.next; n != null; e = n, n = n.next) {
int nextHighBit = n.hash & oldCapacity;
if (nextHighBit != highBit) {
if (broken == null)
newTable[j | nextHighBit] = n;
else
broken.next = n;
broken = e;
highBit = nextHighBit;
}
}
if (broken != null)
broken.next = null;
}

### 解决方案

1.Hashtable替换HashMap
2.Collections.synchronizedMap将HashMap包装起来

Map m = Collections.synchronizedMap(new HashMap());

synchronized(m) {
......
}

3.ConcurrentHashMap替换HashMap