什么是 fail-fast?什么是 fail-safe?

💡 核心结论:一句话先记住

它们是 Java 集合在被遍历时,面对别人插队修改数据采取的两种完全相反的态度

  • fail-fast(快速失败): 脾气暴躁,眼里不容沙子。遍历时只要发现有人偷偷改了数据,立刻撂挑子不干,抛出异常
  • fail-safe(安全失败): 脾气温和,佛系包容。你想改随你改,老子复制一份副本慢慢看,绝对不抛异常。

🔍 深度大白话解析

1. 脾气暴躁的 fail-fast(代表:ArrayList、HashMap)

  • 怎么实现的: 它们内部有一个"记账本"(modCount)。只要有人增加或删除了元素,账本上的修改次数就会加 1。
  • 翻车现场: 你在用 for-each 兴高采烈地遍历元素,每走一步,都会对一下账本。如果突然发现账本数字变了(说明有人在暗中修改),它就会觉得"数据不安全了",当场甩脸子抛出经典的 ConcurrentModificationException 异常。
  • 写代码大坑: 很多人喜欢在 for 循环里直接调用 list.remove() 删元素,这就是典型的"在遍历时改账本",百分之百直接报错

2. 稳如老狗的 fail-safe(代表:CopyOnWriteArrayList、ConcurrentHashMap)

  • 怎么实现的: 它采用的是"影分身之术"。
  • 翻车现场: 当你开始遍历时,它会偷偷把当前的数据复制一份(副本)。你接下来遍历的其实是这个"副本",而别人如果去修改、删除元素,改的是"原本"。
  • 代价: 因为两者互不干扰,所以它绝对不会抛异常 。但缺点也很明显:第一,每次复制副本非常吃内存;第二,你遍历时读到的可能是"老数据"(弱一致性),别人新加进去的东西你可能看不见。

🛠️ 工作中怎么安全地"边遍历边删除"?

这是面试和写代码最常遇到的场景,有三种正确姿势:

  • 姿势一(单线程推荐): 不要用集合自带的 remove,改用迭代器自带的 iterator.remove()。因为迭代器自己删的时候会主动把账本对齐,不会触发暴脾气。
  • 姿势二(Java 8+ 推荐): 直接一行代码搞定:list.removeIf(e -> 条件),底层已经帮你封装好了安全机制。
  • 姿势三(多线程推荐): 直接换用并发安全集合,比如把 ArrayList 换成 CopyOnWriteArrayList

🎯 秒记口诀

fail-fast账本不对就抛错,直接删除必着魔;

fail-safe 复制副本不报错,数据过期要记着。

单线程删找迭代(Iterator),多线程用并发包!

相关推荐
FreeTinker5 分钟前
Java文件服务器的技术选型与实现路径:从嵌入式工具到企业级系统
java·服务器·开发语言
ly768918 分钟前
Java 21 到 Java 26 新特性详解:虚拟线程、模式匹配、结构化并发、HTTP/3 与 AOT
java·jvm
我星期八休息36 分钟前
Linux I/O多路转接—epoll
java·linux·运维·服务器·开发语言·jvm·算法
学长毕业设计1 小时前
基于springboot的云南中草药知识普及管理网站的设计与开发(源码+文档+讲解视频)
java·spring boot·后端
大模型码小白1 小时前
AI 提示词专栏:使用系统指令(System Prompt)实现全局约束
java·大数据·运维·开发语言·人工智能·python·prompt
cxoptics1 小时前
蓝宝石的轴向在窗片和偏振片中起的作用
java
wuminyu1 小时前
Java FFM处理网络读写事件源码剖析
java·linux·c语言·jvm·c++
小江的记录本2 小时前
【AI Agent】《2026年9月 AI Agent全栈开发技术选型专项面试宝典》
java·spring boot·python·spring·ai·面试·ai编程
梦梦代码精2 小时前
《LikeShop全产品技术硬核拆解:ThinkPHP8+Vue3+UniApp架构,私有化部署与二次开发实战指南》
java·低代码·系统架构·php·开源软件
一木 之林2 小时前
C/C++ 面向对象编程(OOP)(进阶)
java·c语言·c++