Java怎么实现一个线程安全的计数器?以下是实现线程安全计数器的几种常见方法,根据场景选择最优方案:
方法1:使用 AtomicLong
(推荐轻量级场景)
import java.util.concurrent.atomic.AtomicLong;
public class AtomicCounter {
private final AtomicLong count = new AtomicLong(0);
public void increment() {
count.incrementAndGet(); // 原子性+1
}
public long get() {
return count.get();
}
}
特点:
- 基于CAS(Compare-And-Swap)实现,无锁竞争,高性能
- 适合低/中并发场景(如QPS <10万)
方法2:synchronized
关键字
public class SynchronizedCounter {
private long count = 0;
public synchronized void increment() {
count++; // 同步块保证原子性
}
public synchronized long get() {
return count;
}
}
特点:
- 简单直接,但锁粒度粗,高并发时性能下降
- 适合代码维护性优先的场景
方法3:LongAdder
(推荐高并发场景)
import java.util.concurrent.atomic.LongAdder;
public class LongAdderCounter {
private final LongAdder count = new LongAdder();
public void increment() {
count.increment(); // 分段CAS降低竞争
}
public long get() {
return count.sum();
}
}
特点:
- JDK8+ 引入,分段累加避免CAS自旋,吞吐量极高
- 适合超高并发计数(如秒杀系统计数器)
方法4:ReentrantLock
(需灵活控制时)
import java.util.concurrent.locks.ReentrantLock;
public class LockCounter {
private long count = 0;
private final ReentrantLock lock = new ReentrantLock();
public void increment() {
lock.lock();
try {
count++;
} finally {
lock.unlock(); // 必须finally释放锁
}
}
}
特点:
- 比
synchronized
更灵活(可尝试锁、可中断等) - 适合需要复杂锁控制的场景
性能对比(参考基准测试)
实现方式 | 10线程/100万次操作耗时 | 适用场景 |
---|---|---|
AtomicLong | ~120ms | 通用场景 |
LongAdder | ~50ms | 超高并发写入 |
synchronized | ~600ms | 低并发或遗留系统 |
ReentrantLock | ~300ms | 需要锁高级功能时 |
选型建议:
- 优先选
LongAdder
(JDK8+)或AtomicLong
- 需要阻塞控制时再用
ReentrantLock
- 传统项目可用
synchronized
简化代码