使用ConcurrentHashMap结合compute或merge方法可实现线程安全的并发计数,普通场景推荐merge简化逻辑,高频更新场景建议搭配LongAdder以降低CAS竞争,提升性能。

在高并发场景下,使用普通的HashMap或synchronized关键字实现计数容易引发线程安全问题或性能瓶颈。Java中的ConcurrentHashMap结合原子操作,是实现高效并发计数的理想选择。
使用ConcurrentHashMap配合putIfAbsent和compute实现线程安全计数
ConcurrentHashMap本身不提供原子递增操作,但可以通过其提供的原子性方法如compute、merge或putIfAbsent来实现安全的计数逻辑。
以下是一个基于compute方法实现的并发计数器示例:
import java.util.concurrent.ConcurrentHashMap; public class ConcurrentCounter { private final ConcurrentHashMap<String, Long> counter = new ConcurrentHashMap<>(); public void increment(String key) { counter.compute(key, (k, oldValue) -> oldValue == null ? 1L : oldValue + 1); } public long get(String key) { return counter.getOrDefault(key, 0L); } }
在这个例子中,compute方法保证了读-改-写操作的原子性,多个线程同时调用increment不会导致数据错乱。
立即学习“Java免费学习笔记(深入)”;
使用merge方法简化计数逻辑
ConcurrentHashMap的merge方法更适合计数场景,它能更简洁地实现相同功能:
public void increment(String key) { counter.merge(key, 1L, Long::sum); }
这行代码表示:如果key不存在,插入值为1;如果已存在,则将原值与1相加后更新。整个操作是线程安全的。
应对更高性能需求:结合LongAdder
当计数频率极高时,多个线程频繁更新同一个key可能导致CAS竞争激烈。可以将value类型换成LongAdder,它专为高并发累加设计:
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.LongAdder; public class HighPerformanceCounter { private final ConcurrentHashMap<String, LongAdder> counter = new ConcurrentHashMap<>(); public void increment(String key) { counter.computeIfAbsent(key, k -> new LongAdder()).increment(); } public long get(String key) { LongAdder adder = counter.get(key); return adder == null ? 0L : adder.sum(); } }
LongAdder通过分段累加降低多线程冲突,读取时再汇总各段结果,在写多读少的场景下性能显著优于AtomicLong。
基本上就这些。根据实际并发强度选择合适的方式:普通场景用merge即可,超高频更新建议搭配LongAdder。ConcurrentHashMap的分段锁机制加上这些原子操作,足以支撑大多数高并发计数需求。


