注释为什么不能依赖fail-fast
小程序websocket心跳库——websocket-heartbeat-miniprogram
我的看法
fail-fast是什么就不多诠释了,应当注重到的是(以ArrayList为例):modCount位于AbstractList中,
protected transient int modCount = 0;
并没有volatile润饰,因而当两线程是共用同一个cpu时才会抛出并发修正非常。比方:
线程1正在用迭代器来读,此时共用同一个cpu**的线程2来修正list,使得modCount++。因为共用同一个cpu,那末所修正的是**同一个缓存中的modCount,如许使得线程1下一次搜检时发明与期望值不等,便会抛出非常
final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); }
然则假如线程2用的是差别的cpu,而modCount又没有volatile润饰,那末线程2对modCount的修正不知道什么时刻才会写回主存,也不知道什么时刻线程1才会从新从主存中读取modCount。
因而涌现并发修正也不一定会抛非常,而实在只需违背划定规矩,单线程还是会抛出并发修正非常
public static void main(String[] args) { ArrayList<Integer> list = new ArrayList<>(); list.add(1); list.add(2); Iterator iterator=list.iterator(); while(iterator.hasNext()){ iterator.next(); list.add(3); } } // Exception in thread "main" java.util.ConcurrentModificationException // at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909) // at java.util.ArrayList$Itr.next(ArrayList.java:859) // at github.com.AllenDuke.concurrentTest.future.FutureTest.main(FutureTest.java:29)
然则线程用哪一个cpu执行任务是不可知的。
所见的网上的答案
注重:这里非常的抛出前提是检测到modCount != expectedModCount这个前提。假如鸠合发生变化时修正modCount值恰好又设置为了expectedModCount值,则非常不会抛出。因而,不能依赖于这个非常是不是抛出而举行并发操纵的变成,这个非常只发起用于检测并发修正的bug。
这句话会误让人认为,线程进去修正的时刻+1,修正完就-1。但实际上modCount是只会递增的,至少在jdk1.8中没有发明modCount--或是--modCount。应用反射能够看出并非退出要领就-1,以下:
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException { ArrayList<Integer> list = new ArrayList<>(); Class c= AbstractList.class; Field modCountField = c.getDeclaredField("modCount"); modCountField.setAccessible(true); for (int i = 0; i < 5; i++) { list.add(i); System.out.println(modCountField.get(list)); } } // 1 // 2 // 3 // 4 // 5
或许这句话的意义是两个线程同时+1,如许的话,根本原因就和我的看法一致了。
硬核抠门程序员,每天程序为小学生出数学题!