Java集合的快速失败机制 “fail-fast”

Java集合的快速失败机制 “fail-fast”

Java集合中的快速失败(fail-fast)机制是指在使用迭代器对集合进行遍历时,如果集合的结构被修改(增加、删除元素等),则迭代器会立即抛出ConcurrentModificationException异常,这种设计是为了避免不确定性和错误的结果。

工作原理

快速失败机制的实现依赖于集合中的一个称为modCount的计数器。modCount是集合中一个用来记录集合结构修改次数的变量。每当集合结构发生变化(如添加、删除元素)时,modCount的值就会增加。当创建迭代器时,迭代器会记录下当前的modCount值作为自己的一个状态值(称为expectedModCount)。在迭代过程中,每次使用迭代器获取下一个元素之前,都会检查modCount是否等于expectedModCount,如果不等,说明集合的结构在迭代过程中被修改了,迭代器就会抛出ConcurrentModificationException

影响

快速失败机制存在于Java集合框架的很多实现中,如ArrayListHashMap等。但是,并非所有的集合实现都是快速失败的。例如,ConcurrentHashMapCopyOnWriteArrayList等并发集合就采用了不同的策略来允许并发修改。

应对策略

当需要在遍历过程中修改集合时,可以采用以下几种策略来避免ConcurrentModificationException

  1. 使用并发集合:选择支持并发修改的集合实现,如ConcurrentHashMapCopyOnWriteArrayList等。

  2. 使用迭代器的remove方法:如果只是需要在迭代时删除元素,可以使用迭代器自己的remove方法,而不是集合的remove方法。迭代器的remove方法会更新expectedModCount值,从而避免异常。

  3. 收集需要修改的元素,迭代完成后统一处理:在迭代过程中,将需要修改的元素收集起来,迭代完成后再对集合进行统一的修改。

示例

List<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
list.add("C++");

Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
    String language = iterator.next();
    if ("Python".equals(language)) {
        iterator.remove(); // 使用迭代器的remove方法
    }
}

快速失败机制是Java集合设计中的一个重要特性,它有助于及早发现并发修改的问题,但同时也要求开发者在使用集合时更加注意操作的安全性。

ConcurrentHashMap和CopyOnWriteArrayList等并发集合就采用了不同的策略来允许并发修改

ConcurrentHashMapCopyOnWriteArrayList是Java并发包java.util.concurrent中提供的两种线程安全的集合,它们采用了不同的策略来允许并发的读写操作,从而避免了快速失败(fail-fast)机制导致的ConcurrentModificationException

ConcurrentHashMap

ConcurrentHashMap是一个线程安全的哈希表,用于替代同步的HashMap(通过Collections.synchronizedMap方法包装得到)。它采用了分段锁(Segmentation Locking)的策略来提高并发访问的效率。

  • 分段锁ConcurrentHashMap内部维护了一个分段锁的数组,每个分段锁管理哈希表的一部分数据。当进行插入、删除等修改操作时,只需要锁定对应的分段,而不是整个哈希表。这样,不同的线程可以同时操作哈希表的不同部分,从而提高并发性能。
  • 无锁读取:对于读操作,ConcurrentHashMap允许多个线程同时无锁访问,因为它对数据的修改操作能够保证数据的一致性和可见性。

CopyOnWriteArrayList

CopyOnWriteArrayList是一个线程安全的列表,用于替代同步的ArrayList。它采用了写时复制(Copy-On-Write)的策略来实现线程安全。

  • 写时复制:当需要修改列表(如添加、删除、设置元素)时,CopyOnWriteArrayList会先复制一份当前的数据,然后在这份复制的数据上进行修改操作,修改完成后再将原数据引用指向新的复制数据。这样,读操作总是在不变的数据快照上进行,无需加锁,从而实现了高效的并发读取。
  • 适用场景:由于写操作需要复制整个底层数组,因此CopyOnWriteArrayList适用于读多写少的并发场景。

总结

  • ConcurrentHashMap通过分段锁的策略,实现了高效的并发更新操作,同时允许多线程无锁地进行读取操作。
  • CopyOnWriteArrayList通过写时复制的策略,保证了并发读的高效性,适用于读多写少的场景。
  • 这两种集合都避免了快速失败机制,提供了更强的并发性能和数据一致性保证。然而,它们的实现策略也决定了各自的使用场景和性能开销,开发者在选择使用时需要根据实际需求做出合理的决策。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值