同步容器通过对象级 synchronized 锁导致高竞争、低并发;ConcurrentHashMap 读操作无锁、分段/细粒度锁提升性能;putIfAbsent 直接插入预计算值,computeIfAbsent 按需调用函数生成值。

Java同步容器的底层锁机制怎么影响性能
同步容器如 Vector、Hashtable 和 Collections.synchronizedList() 本质是用 synchronized 方法或代码块包裹所有公共操作,锁粒度是整个对象。这意味着即使两个线程分别读写不同索引的 Vector,也会互相阻塞。
-
Vector的add()、get()、size()全部加在this上,无法并发执行 -
Collections.synchronizedMap(new HashMap())同样对每个方法单独同步,但迭代时仍需手动同步:必须用synchronized(map) { ... }包裹iterator(),否则抛ConcurrentModificationException - 高并发下吞吐量远低于
ConcurrentHashMap,尤其在读多写少场景——同步容器读操作也被锁住,而ConcurrentHashMap读操作无锁
ConcurrentHashMap 的 putIfAbsent 和 computeIfAbsent 区别在哪
这两个方法都用于条件写入,但语义和执行时机不同:
-
putIfAbsent(K key, V value):只接受已计算好的value,原子判断 key 是否不存在,若不存在则直接插入;适合值构造开销小、无副作用的场景 -
computeIfAbsent(K key, Function super K, ? extends V> mappingFunction):仅当 key 不存在时才调用mappingFunction计算值,且该函数在持有内部段锁(JDK8+为Node级锁)期间执行;适合值需动态构建(如查数据库、解析 JSON),且希望避免重复计算 - 注意:
mappingFunction内不能调用本ConcurrentHashMap的其他修改方法(如put),否则可能死锁;也不应有阻塞或长耗时逻辑,会拖慢整个桶的写操作
ConcurrentHashMap> cache = new ConcurrentHashMap<>(); // 安全:lambda 在锁内执行,只对当前 key 所在 bin 加锁 cache.computeIfAbsent("user:1001", k -> fetchRolesFromDB(k));
CopyOnWriteArrayList 为什么适合读多写少但不适合实时性要求高的场景
CopyOnWriteArrayList 每次写操作(add、remove)都会复制整个底层数组,读操作则直接访问当前数组引用,无锁且不会阻塞。
AJAX即“Asynchronous Javascript And XML”(异步JavaScript和XML),是指一种创建交互式网页应用的网页开发技术。它不是新的编程语言,而是一种使用现有标准的新方法,最大的优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容,不需要任何浏览器插件,但需要用户允许JavaScript在浏览器上执行。《php中级教程之ajax技术》带你快速
- 优点:遍历时完全不怕
ConcurrentModificationException,适合监听器列表、回调注册等写极少、读极频繁且允许短暂 stale 的场景 - 缺点:写操作内存与 CPU 开销大;新写入的元素对正在遍历的迭代器不可见——即“最终一致性”,不是实时可见
- 不能用于需要强一致性的计数、状态同步等逻辑;例如
list.size()返回的是快照大小,但紧接着调用list.get(0)可能越界(因其他线程刚清空了 list)
BlockingQueue 实现类该怎么选:ArrayBlockingQueue vs LinkedBlockingQueue vs SynchronousQueue
三者都是线程安全的阻塞队列,但数据结构和行为差异显著:
立即学习“Java免费学习笔记(深入)”;
-
ArrayBlockingQueue:固定容量、基于数组、单锁(ReentrantLock),生产/消费共用一把锁;吞吐量中等,内存占用可控,适合容量明确、追求稳定延迟的场景 -
LinkedBlockingQueue:可选容量(默认Integer.MAX_VALUE)、基于链表、双锁(takeLock和putLock分离);读写可并行,吞吐更高,但可能因无界导致 OOM -
SynchronousQueue:不存储元素,每个put()必须等待配对的take(),反之亦然;适合任务交接(如Executors.newCachedThreadPool()),零缓冲,延迟最低,但使用不当易造成线程阻塞堆积
// 错误:无界 LinkedBlockingQueue 在高吞吐下游阻塞时会无限堆积 new LinkedBlockingQueue<>(); // 应显式指定 capacity // 正确:带界队列 + 拒绝策略更可控 new ArrayBlockingQueue<>(1000);真正容易被忽略的是锁粒度与一致性模型的隐含契约:比如
ConcurrentHashMap 不保证全局迭代一致性,CopyOnWriteArrayList 的写操作会触发 full copy,而 SynchronousQueue 表面轻量,实则把背压完全交给了线程调度。选错一个,问题往往在压测后期才暴露。









