原文来自于:zha-ge.cn/java/77

原来 Java 里线程安全集合有这么多种

有那么一天,咖啡喝多了,脑袋嗡嗡响,领导突然“温柔”地甩过来一坨需求:“你这List用的安全吗?多线程下会不会爆炸?” 我一口激浪差点喷屏幕,线程安全集合,这不是老生常谈嘛。可是等我翻代码,才发现自己其实只认识 Collections.synchronizedListVector,其他的都进垃圾回收站了。哎,这锅不能背,得扒一扒 Java 里的线程安全集合到底有几路豪杰。


初见江湖:这些名字我都见过?

Java 集合家族其实超级大,线程安全的那些,堪比武林门派,各有绝技。

  • Vector, Hashtable 这些上古遗迹,虽然老,但能保命。
  • Collections.synchronizedXXX 工厂方法,给老集合套个线程安全“特效皮肤”。
  • ConcurrentHashMap, CopyOnWriteArrayList 等并发大佬,JDK5后出道,秒杀前辈。

我还腾了个小表格,请叫我表哥:

集合名线程安全性优势劣势
Vector安全祖传防爆,简单易懂性能糟糕
Collections.synchronizedList安全易于转换,老代码福音性能一般,颗粒粗
ConcurrentHashMap超级安全读多写少场景无敌,细粒度锁写多可能瓶颈
CopyOnWriteArrayList读安全读写分离,读场景快写操作开销大

砸场子的瞬间

我一开始跑路 Collections.synchronizedList,写了个多线程测试自信满满,结果直接春哥再临。问题出在哪?

List<String> syncList = Collections.synchronizedList(new ArrayList<>());
for (int i = 0; i < 1000; i++) {
    new Thread(() -> {
        syncList.add(Thread.currentThread().getName());
    }).start();
}
// 等等再遍历
for (String name : syncList) {
    System.out.println(name);
}

别问我为啥会ConcurrentModificationException,问就是for-each遍历没加锁。线程安全这个事儿,还得自己上心啊!上了锁,世界才安静:

synchronized (syncList) {
    for (String name : syncList) {
        System.out.println(name);
    }
}

但这不优雅啊朋友,终于理解为啥 CopyOnWriteArrayList 会受宠。


踩坑瞬间

  • 以为加了 Collections.synchronizedList 就万事大吉,结果遍历都没锁上,直接爆炸。
  • Vector 还能用吗?能,但写多别碰它,性能跑不过 Concurrent 家族。
  • CopyOnWriteArrayList 很香,但写操作多会让你怀疑人生,因为每次写都要拷贝,内存都差点不够用了。
  • ConcurrentHashMap 的 Key/Value 不能随便为 null,不是所有 Map 都惯着你。

经验启示

  • 不是加了“线程安全”标签就能无脑用,遍历时记得手动加锁,尤其是同步包装类。
  • 读多写少就用 CopyOnWriteArrayList/Set/Map,写多还是 Concurrent 家族靠谱。
  • Vector、Hashtable 真的是爷青结,只适合和遗留系统“深情对望”。
  • 别的门派不懂的,别忘了 JavaDoc 黄金屋,多看看说明书,比我瞎踩坑省时多了。

最后,我现在面对线程安全集合都学会了一个骚操作:先问,啥场景?多读还是多写?要啥功能? 真不确定,用 Concurrent 系列,起码不会坑队友。 写代码就是这样嘛,边挨锤边成长,踩坑万岁!

本站提供的所有下载资源均来自互联网,仅提供学习交流使用,版权归原作者所有。如需商业使用,请联系原作者获得授权。 如您发现有涉嫌侵权的内容,请联系我们 邮箱:[email protected]