应使用 java.util.concurrent 包中的并发集合类;Vector 和 Hashtable 因全局锁导致高并发性能差,Hashtable 还不支持 null 且已过时;Collections.synchronizedXxx() 仅保障单操作原子性,复合操作仍需手动同步;ConcurrentHashMap、CopyOnWriteArrayList、ConcurrentLinkedQueue 等针对不同场景优化,性能与安全性远超传统同步包装类。

Vector 和 Hashtable 是线程安全的,但别用
它们确实是线程安全的——所有 public 方法都加了 synchronized,但代价是整个对象一把锁。高并发下,读写全排队,吞吐量断崖式下跌。
- Vector 的
add()、get()、size()全部串行执行,哪怕只是读 100 次,也得抢同一把锁 - Hashtable 不允许
null键或值,和现代代码习惯冲突;且已标记为 legacy,JDK 文档里明确建议用ConcurrentHashMap - Stack 继承自 Vector,同样一把锁 + 过时 API(推荐用
Deque实现如ArrayDeque)
Collections.synchronizedXxx() 包一层就安全?不完全是
它只是给每个方法套了个 synchronized(this),看起来“线程安全”,但复合操作依然裸奔。比如“检查是否存在再添加”,两步之间完全可能被其他线程插队。
-
Collections.synchronizedMap(new HashMap()):单个put()或get()是安全的,但if (!map.containsKey(k)) map.put(k, v);非线程安全 - 遍历时必须手动同步:要用
synchronized (map) { for (Entry e : map.entrySet()) { ... } },漏掉就可能抛ConcurrentModificationException - 本质是“伪安全”——适合低并发、简单场景;一上生产,容易埋雷
真正该用的:java.util.concurrent 里的那几个
这些不是简单加锁,而是按场景做了算法级优化,性能差一个数量级都不夸张。
-
ConcurrentHashMap:分段锁(JDK 8+ 改为 CAS + synchronized 优化桶头),支持 16 路(默认)并发写,读操作完全无锁。替代HashMap的唯一合理选择 -
CopyOnWriteArrayList:写时复制整数组,适合 读远多于写 的场景(如监听器列表)。写操作开销大,千万别在循环里反复add() -
ConcurrentLinkedQueue:无锁队列,靠 CAS 循环重试,适合高并发、非阻塞的生产者-消费者。不提供size()的精确值(因为要遍历,不保证原子) -
BlockingQueue实现类(如ArrayBlockingQueue、LinkedBlockingQueue):带阻塞语义,适合需要“等有空位再放”或“等有数据再取”的协作逻辑
选错集合的典型症状
不是报错才叫出问题,很多是性能卡顿、结果偶发错乱,排查起来像捉鬼。
立即学习“Java免费学习笔记(深入)”;
- 用
HashMap在多线程里 put/get —— 可能死循环(JDK 7)、扩容异常(JDK 8+ 改善但仍不安全) - 用
ArrayList多线程 add ——IndexOutOfBoundsException或数据丢失,尤其在扩容临界点 - 用
ConcurrentHashMap的size()做条件判断 —— 它返回的是估算值,不是实时精确计数 - 在
CopyOnWriteArrayList上调iterator().remove()—— 不生效,因为迭代器基于快照,remove 是空操作
线程安全从来不是“挑个名字带 Concurrent 就完事”,关键看读写比例、是否需要阻塞、要不要强一致性。这几个点没想清楚,换再“高级”的类也白搭。










