今天电话面试终端开发岗被问到了这题,怎奈何我菜的一笔,没答上来,特来学习一番,果然做了一年底软现在只会配寄存器了!!
言归正传,其实这题是想问你三点:1、hashmap插入的时候为什么是线程不安全的2、hashmap删除的时候为什么是线程不安全的3、hashmap resize的时候为什么是线程不安全的?
首先要明确什么是线程安全:也就是在多线程的情况下能不能保证资源的互斥。(这儿可能又会问synchronized与Lock的区别与使用)
对于插入来说put会调用 addEntry:
void addEntry(int hash, K key, V value, int bucketIndex) {
Entry<K,V> e = table[bucketIndex];
table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
if (size++ >= threshold)
resize(2 * table.length);
}
table[bucketIndex]假如被两个线程同时获取就会导致某一进程的数据丢失。
ps:
protected Entry(int hash,K key,V value,Entry<K,V>next) {
this.hash=hash;
this.key=key;
this.value=value;
this.next=next;//从Entry构造函数看是不是可以说明是从头结点插入的呢?
}
2、删除会调用removeEntryForKey:
final Entry<K,V> removeEntryForKey(Object key) {
int hash = (key == null) ? 0 : hash(key.hashCode());
int i = indexFor(hash, table.length);
Entry<K,V> prev = table[i];//取到头结点
Entry<K,V> e = prev;
while (e != null) {
Entry<K,V> next = e.next;//下一个结点
Object k;
if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) {
modCount++;
size--;
if (prev == e)
table[i] = next;
else
prev.next = next;
e.recordRemoval(this);
return e;
}
prev = e;
e = next;
}
return e;
}
与put一致也会获取table[i]头结点。
3、当键值对数量超过门限值时会调用resize操作:
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);
table = newTable;
threshold = (int)(newCapacity * loadFactor);
}
当两个线程同时rezise就不知道是哪个数组被留下了。
pps:今天还有许多问题需要闭环,比如hashcode和equals的关系(又忘了)。。。