发布网友 发布时间:2024-10-02 01:11
共1个回答
热心网友 时间:2024-10-25 07:35
在非同步容器中,例如ArrayList与HashMap,其使用场景是在单线程环境中,抛concurrentModificationException是为了防止在多线程场景下容器使用出现错误。例如第一个线程读,第二个线程删除了一个元素,导致第一个线程抛出了数组越界异常。这只是个例子,对于多线程的不可见性还会出现hashmap扩容死循环等问题,所以抛concurrentModificationException是为了避免更多的错误发生。
HashTable是一个同步容器,但是因为HashTable生成Iterator迭代器时,是new一个迭代器对象。
所以多线程环境下,其他线程并不能修改本线程迭代器的exceptModCount,所以当next或hasNext时依然会报异常。
疑问:作为同步容器为什么还需要报此异常?
想必都知道HashTable的get,put,remove操作都是对整个表上锁的,也就是remove方法是synchronized方法,由此做到同步。 但是 !Iterator的方法并没有做到同步,甚至同一个线程获取两次iterator是两个iterator对象,也就是说当其他线程在remove的时候,该线程依然可能通过iterator对象的next方法抛出数组越界等异常。
1.因为concurrentHashMap读写不互斥,所以当其他线程正在修改容器中部分副本时,读操作不受影响。
2.table用violatile修饰,使得读操作可以收到更新。加上hapend-before机制,避免读取到更新前的数据。
注意 :violatile修饰数组时,修饰的是数组的地址而不是数组的元素。
既然volatile修饰数组对get操作没有效果那加在数组上的volatile的目的是什么呢?
其实就是为了使得Node数组在扩容的时候对其他线程具有可见性而加的volatile
3.由于读写机制都是通过violatile实现的,所以在迭代的时候保证了数据的可见性,因此不会出现数组越界等异常,所以不需要抛concurrentModificationException