Java线程安全集合选型需按场景:读多写少用CopyOnWriteArrayList,高并发读写用ConcurrentHashMap,强一致性用BlockingQueue,简单共享用AtomicInteger等原子类。
Java中选择线程安全的集合,关键不是“有没有锁”,而是看场景:读多写少、写频繁、需要强一致性、还是允许弱一致性?不同集合的设计目标差异很大,选错不仅性能差,还可能出并发bug。
适合迭代远多于增删的场景,比如监听器列表、配置白名单。它的原理是每次写操作都复制整个数组,读完全无锁、高性能,但写操作开销大、内存占用高。
ConcurrentModificationException,也不需要加锁这是最常用的线程安全 Map,JDK 8 后基于 CAS + synchronized 分段锁优化,读操作几乎无锁,写操作只锁对应 bin 链表或红黑树头节点。
containsKey + put 这类复合操作的原子性,需用 computeIfAbsent 或 merge
entrySet().forEach(...) 是弱一致性快照,可能看不到最新写入,也不会阻塞写入size() 判断是否为空——它返回估算值;要用 isEmpty()(它是准确的)比如 ArrayBlockingQueue(有界、可重入锁)、LinkedBlockingQueue(默认无界、读写双锁)、PriorityBlockingQueue(带排序的无界队列)。它们专为生产者-消费者模型设计,支持阻塞插入/获取、超时等待、容量控制。
poll() 空转,应使用 take() 或带 timeout 的 poll(long, TimeUnit)
SynchronousQueue 不存储元素,每个 put 必须配一个 take,适合任务交接场景(如 newCachedThreadPool 内部使用)如果只是做计数器、开关标志、单个对象引用更新,比用 ConcurrentHashMap 或包装成 synchronized 方法更轻量、更高效。
AtomicInteger 的 incrementAndGet()、compareAndSet() 是无锁且原子的AtomicReference
可用于替换整个集合引用(注意内部 List 本身仍需线程安全)StampedLock 或显式锁不复杂但容易忽略:没有“万能线程安全集合”,只有“更适合当前访问模式”的集合。先理清读写比例、是否需要阻塞、一致性要求、内存敏感度,再对照特性选型,比盲目套用 synchronized 包装或一律上 ConcurrentHashMap 更可靠。