concurrenthashmap 不能用 put 替代 computeifabsent,因为 put 无条件覆盖,而 computeifabsent 仅在 key 不存在时执行一次 lambda 构造值,避免多线程重复创建对象,适用于缓存初始化等场景。

ConcurrentHashMap 为什么不能直接用 put 替代 computeIfAbsent
因为 put 是无条件覆盖,而 computeIfAbsent 在 key 不存在时才计算并插入——这在缓存初始化、单例工厂等场景里能避免重复构造对象。常见错误是写成:map.put(key, new ExpensiveObject()),结果多个线程同时触发,创建了多个实例。
- 如果值构造开销大,必须用
computeIfAbsent,它内部加锁粒度更细,且保证只执行一次 lambda -
putIfAbsent只适合“已有现成值”的情况;computeIfAbsent才是“按需生成”的正确姿势 - JDK 8+ 才有
computeIfAbsent;JDK 7 只能手写双重检查 +putIfAbsent循环重试
CountDownLatch 和 CyclicBarrier 都能等线程,区别在哪
看等待逻辑:一个等“事件完成”,一个等“人齐”。比如启动服务时要等 3 个模块初始化完毕,用 CountDownLatch;而多个线程要协作执行多轮计算(每轮都得等所有人到齐),就得用 CyclicBarrier。
-
CountDownLatch是一次性门栓,countDown()减到 0 后不可重置;CyclicBarrier可复用,await()返回即重置计数 -
CyclicBarrier支持在所有人到达时触发一个Runnable(比如汇总数据),CountDownLatch没这能力 - 如果某线程在
await()时中断或超时,CyclicBarrier会让所有等待线程抛BrokenBarrierException,这是显式失败信号,别忽略处理
AtomicInteger 的 incrementAndGet 真的比 synchronized 快吗
在低竞争下快得多,高竞争下可能反而慢——因为底层依赖 CPU 的 cmpxchg 指令,反复失败重试会浪费 cycles。不是“用了原子类就一定高效”,要看实际线程争抢程度。
千博购物系统.Net能够适合不同类型商品,为您提供了一个完整的在线开店解决方案。千博购物系统.Net除了拥有一般网上商店系统所具有的所有功能,还拥有着其它网店系统没有的许多超强功能。千博购物系统.Net适合中小企业和个人快速构建个性化的网上商店。强劲、安全、稳定、易用、免费是它的主要特性。系统由C#及Access/MS SQL开发,是B/S(浏览器/服务器)结构Asp.Net程序。多种独创的技术使
- 单核或极少线程更新时,
AtomicInteger基本无锁,性能碾压synchronized - 上百线程高频更新同一个变量,CAS 失败率飙升,此时用
LongAdder(JDK 8+)更合适,它通过分段累加降低冲突 -
incrementAndGet返回新值,getAndIncrement返回旧值,别用反;很多 bug 就是因为没看清返回值语义
BlockingQueue 的 offer、put、add 到底该选哪个
看你要不要阻塞、要不要丢弃、要不要抛异常。这三个方法行为完全不同,混用会导致队列满时程序卡死或静默失败。
立即学习“Java免费学习笔记(深入)”;
-
add(e):队列满时直接抛IllegalStateException,基本不用,太暴力 -
offer(e):非阻塞,成功返回true,满则返回false,适合做快速试探 -
put(e):阻塞直到有空间,适合生产者不能丢数据的场景;但若消费者长期卡住,生产者线程会被 hang 住,得配超时用offer(e, timeout, unit)
CyclicBarrier 的“可重用”和 Phaser 的“动态注册”差着一层抽象;又比如 CopyOnWriteArrayList 只适合读远多于写的场景,写多时内存和 GC 压力会突然变大。用之前先想清楚:你真正要等的是什么,真正要保护的是哪块状态,真正不能容忍的是哪种失败。









