第2题Iterator的fail-fast和fail-safe机制有什么区别回答概念fail-fast快速失败遍历ArrayList的时候如果有其他线程偷偷修改了集合比如增删改就会直接抛出异常告诉你“别乱动”fail-safe安全失败遍历CopyOnWriteArrayList的时候允许你边遍历边修改集合因为它会自己维护一份副本用来遍历而原始集合可以随意修改。区别fail-fast机制底层通过一个modCount变量记录集合的修改次数。如果遍历时发现modCount变了就抛出ConcurrentModificationException。注意这里说的其他线程偷偷修改其实不太准确。fail-fast主要是检测同一个线程在遍历过程中对集合做了结构性修改比如add、remove或者其他线程并发修改。但最经典的场景是单线程里自己边遍历边修改也会抛异常。示例ListStringlistnewArrayList();list.add(a);for(Strings:list){list.add(new);// 抛出ConcurrentModificationException}原理补充迭代器在创建时会记录当前的modCount每次调用next()或remove()时都会检查modCount是否和预期一致。不一致就说明集合被修改过了立马抛异常。fail-safe机制使用CopyOnWriteArrayList时迭代器会复制一份当前集合的快照用于遍历而原始集合可以继续被修改。注意不是每次修改都复制整个数组这么夸张。CopyOnWriteArrayList是写时复制——只有调用add、set、remove这类修改操作时才会复制一份新数组在新数组上修改然后把引用指向新数组。读操作包括遍历完全不需要复制直接读原数组。示例ListStringlistnewCopyOnWriteArrayList();list.add(a);for(Strings:list){list.add(new);// 不会抛异常但遍历的是旧快照新加的new本次遍历看不到}面试官视角面试官可能会问“为什么fail-fast会抛出异常”答因为fail-fast通过modCount字段检测集合的结构性修改次数一旦发现迭代器记录的expectedModCount和实际的modCount不一致就会认为存在并发修改或非法操作从而抛出ConcurrentModificationException。面试官可能会追问“fail-safe为什么性能开销大/性能差”答因为写操作add、remove等时需要复制整个底层数组尤其是在数据量较大时时间和空间开销显著增加。但读操作完全不受影响所以读多写少的场景才适合用它。面试官可能会问“实际开发中如何选择这两种机制”答如果需要高并发支持且读多写少选择fail-safe机制如CopyOnWriteArrayList、ConcurrentHashMap的迭代器也是fail-safe的。如果是单线程或者写多读少的场景用普通的ArrayList、HashMap就行它们都是fail-fast的。但要注意别在遍历过程中修改集合非要改的话可以用迭代器自己的remove()方法或者遍历完再改。