面試高頻考點(diǎn)!CopyOnWriteArrayList 到底是什么?
面试高频考点!CopyOnWriteArrayList 到底是什么?
先来个场景,某次面试,我原本信心满满,BAT大厂二面官,眉头一扬直接来了句:“那你说说 CopyOnWriteArrayList 吧。”瞬间脑子嗡了一下,这玩意儿不是数组那一挂的么,居然还能成为拷问灵魂的问题!好了,今天就来随意聊聊 CopyOnWriteArrayList。如果你也遇到过类似问题,不妨听听我的“踩坑日记”。
其实这个名字,光看 CopyOnWrite 就挺直白了,写的时候才复制。听起来有点像小时候考试,平时作业抄的安心,真遇到老师收本子,才瑟瑟发抖赶紧抄标准答案……
CopyOnWriteArrayList 忍者般的底气
为啥会用它?两个字:线程安全。
还是有人疑惑,这么多集合,为啥就它特别?
- 传统的 ArrayList,都知道,线程不安全。
- Vector?线程安全是安全了点,用的又是笨重的 synchronized,每次加锁解锁,速度慢得像蜗牛。
- CopyOnWriteArrayList 呢?靠的不是锁,而是“写时复制”——只有写的时候才复制一份新数组。平时读就放心老老实实地用,效率高得很。
顺嘴提一句,CopyOnWriteArrayList 最适合“读多写少”的场景。
比如系统有个配置表,万年不改,偏偏读的人特别多,就它香。
踩坑瞬间
我当初第一次用 CopyOnWriteArrayList,想着线程安全,放心大胆往里怼。哪知道,下面这场面直接把我气笑。
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
list.add("蛋炒饭");
list.add("牛奶");
// 每次 add/remove,其实都复制一遍数组
list.remove("蛋炒饭"); // 这一步悄咪咪复制了一份新数组
// ……
问题来了,写操作多起来,内存就猛涨。本来想着省事,没想到一大堆写入,一晚上 jvm 都快被吃挂了。
最迷惑的时候是遍历。
你以为会像普通 ArrayList 那样:
for (String dish : list) {
// 假装有写操作
list.remove(dish);
}
结果 CopyOnWriteArrayList 压根不甩你,遍历期间的写操作,压根不报错,也不会“瞬时生效”,遍历用的是遍历前的旧快照,活脱脱“井水不犯河水”,你删除你自己的,遍历我还是老样子,完全看不到你的骚操作。
这跟 ArrayList 那动不动就 ConcurrentModificationException 的暴脾气完全不一样。
经验启示
让我总结一下血泪教训:
- 别乱用: 只用在读操作远多于写操作的地方。写太多?老老实实乖乖回归锁或者用别的并发集合。
- 遍历场景:
- 遍历时看到的是遍历前的内容,中间搞啥写操作都不影响这个遍历。简直“特务间的备份”。
- 不会抛 ConcurrentModificationException,但也别指望写操作能立马反映出来。
- 内存消耗: 写操作多,复制开销大,尤其是大列表会哭出来。写少读多才是它的主战场。
- 面试提问高频点:
- 与 ArrayList/Vector/其他并发集合的区别
- 内部实现的原理(复制、快照)
- 应用场景举例
写到这里
CopyOnWriteArrayList 这个家伙吧,本质上就像写日记:写的时候影印一份,谁爱怎么改怎么改,看的时候一律享受历史快照,不用担心中间被捣乱。优点爽快,缺点明显,得看清场景再下手。
最后,面试如果遇到,别慌,就聊聊它的底层原理+适用场景+注意点,分分钟给面试官来个灵魂三连(其实我后来就这么糊弄过的,效果还挺好)。
大家伙有啥踩坑经历,也欢迎留言吐槽,我们互相取暖~
——溜了,今晚先不写代码,吃点蛋炒饭压压惊。
共同學(xué)習(xí),寫下你的評(píng)論
評(píng)論加載中...
作者其他優(yōu)質(zhì)文章