為什么拋異常?
在非同步容器中屿聋,例如ArrayList與HashMap,其使用場(chǎng)景是在單線程環(huán)境中,拋concurrentModificationException是為了防止在多線程場(chǎng)景下容器使用出現(xiàn)錯(cuò)誤嘱朽。例如第一個(gè)線程讀,第二個(gè)線程刪除了一個(gè)元素怔接,導(dǎo)致第一個(gè)線程拋出了數(shù)組越界異常搪泳。這只是個(gè)例子,對(duì)于多線程的不可見性還會(huì)出現(xiàn)hashmap擴(kuò)容死循環(huán)等問題扼脐,所以拋concurrentModificationException是為了避免更多的錯(cuò)誤發(fā)生岸军。
為什么HashTable也會(huì)拋此異常?
HashTable是一個(gè)同步容器瓦侮,但是因?yàn)镠ashTable生成Iterator迭代器時(shí)艰赞,是new一個(gè)迭代器對(duì)象。
private <T> Iterator<T> getIterator(int type) {
if (count == 0) {
return Collections.emptyIterator();
} else {
return new Enumerator<>(type, true);
}
}
所以多線程環(huán)境下肚吏,其他線程并不能修改本線程迭代器的exceptModCount方妖,所以當(dāng)next或hasNext時(shí)依然會(huì)報(bào)異常。
疑問:作為同步容器為什么還需要報(bào)此異常罚攀?
想必都知道HashTable的get党觅,put,remove操作都是對(duì)整個(gè)表上鎖的斋泄,也就是remove方法是synchronized方法杯瞻,由此做到同步。但是炫掐!Iterator的方法并沒有做到同步又兵,甚至同一個(gè)線程獲取兩次iterator是兩個(gè)iterator對(duì)象,也就是說當(dāng)其他線程在remove的時(shí)候,該線程依然可能通過iterator對(duì)象的next方法拋出數(shù)組越界等異常沛厨。
private class Enumerator<T> implements Enumeration<T>, Iterator<T> {
Entry<?,?>[] table = Hashtable.this.table;
protected int expectedModCount = modCount;
int index = table.length;
Entry<?,?> entry;
Entry<?,?> lastReturned;
int type;
public T next() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
return nextElement();
}
public T nextElement() {
Entry<?,?> et = entry;
int i = index;
Entry<?,?>[] t = table;
/* Use locals for faster loop iteration */
while (et == null && i > 0) {
et = t[--i];
}
entry = et;
index = i;
if (et != null) {
Entry<?,?> e = lastReturned = entry;
entry = e.next;
return type == KEYS ? (T)e.key : (type == VALUES ? (T)e.value : (T)e);
}
throw new NoSuchElementException("Hashtable Enumerator");
}
為什么concurrentHashMap不會(huì)拋此異常宙地?
1.因?yàn)閏oncurrentHashMap讀寫不互斥,所以當(dāng)其他線程正在修改容器中部分副本時(shí)逆皮,讀操作不受影響宅粥。
2.table用violatile修飾,使得讀操作可以收到更新电谣。加上hapend-before機(jī)制秽梅,避免讀取到更新前的數(shù)據(jù)。
注意:violatile修飾數(shù)組時(shí)剿牺,修飾的是數(shù)組的地址而不是數(shù)組的元素企垦。
既然volatile修飾數(shù)組對(duì)get操作沒有效果那加在數(shù)組上的volatile的目的是什么呢?
其實(shí)就是為了使得Node數(shù)組在擴(kuò)容的時(shí)候?qū)ζ渌€程具有可見性而加的volatile
3.由于讀寫機(jī)制都是通過violatile實(shí)現(xiàn)的晒来,所以在迭代的時(shí)候保證了數(shù)據(jù)的可見性钞诡,因此不會(huì)出現(xiàn)數(shù)組越界等異常,所以不需要拋concurrentModificationException