上一篇:ThreadLocal · 面试:并发编程面试 123 道
同步容器 vs 并发容器
| 类型 | 例子 | 特点 |
|---|---|---|
| 同步容器 | Vector、Hashtable、Collections.synchronizedXxx | 全表/全方法锁,竞争大 |
| 并发容器 | ConcurrentHashMap、CopyOnWriteArrayList | 锁分离/CAS/写时复制,吞吐高 |
Hashtable.size() 需同步:否则与 put 并发时可能读到不一致计数。
ConcurrentHashMap
JDK 7:Segment 分段锁。
JDK 8+:Node 数组 + 链表/红黑树;CAS + synchronized 锁桶头,粒度更细;读大多无锁。
与 Hashtable:Hashtable 锁整张表;CHM 锁桶/ CAS,并发度高。
Collections.synchronizedMap 包装 HashMap,仍是全 map 锁。
CopyOnWriteArrayList
写时复制:写操作复制新数组,读无锁遍历旧数组。
- 适合 读多写少(配置、监听器列表)
- 缺点:写开销大、内存占用、读可能短暂不一致(最终一致)
阻塞队列 BlockingQueue
用于生产者-消费者、线程池任务队列:
| 队列 | 特点 |
|---|---|
ArrayBlockingQueue | 有界数组 FIFO |
LinkedBlockingQueue | 可选有界,链表 FIFO |
SynchronousQueue | 不存元素,直接交接 |
DelayQueue | 延迟到期才能取 |
PriorityBlockingQueue | 优先级无界 |
常用方法:put/take(阻塞)、offer/poll(非阻塞或超时)。
非阻塞并发队列
ConcurrentLinkedQueue:CAS 无锁链表,高并发入队出队。
线程安全 HashMap 选型
- 单线程:
HashMap - 并发读多写少:
ConcurrentHashMap - 需全表锁简单方案:
Collections.synchronizedMap(性能较差) - 不要用
HashMap多线程写(可能死循环/JDK7、数据丢失/JDK8+)
一句话总结
多线程共享 Map 用 ConcurrentHashMap;读多写少列表用 CopyOnWrite;任务排队用 BlockingQueue 配合线程池。