侧边栏壁纸
博主头像
colo

欲买桂花同载酒

  • 累计撰写 1823 篇文章
  • 累计收到 0 条评论

设计一个高并发场景下的线程安全计数器

2025-12-5 / 0 评论 / 4 阅读

题目

设计一个高并发场景下的线程安全计数器

信息

  • 类型:问答
  • 难度:⭐⭐

考点

线程安全,原子操作,并发性能优化,volatile关键字

快速回答

实现高并发线程安全计数器的核心要点:

  • 使用java.util.concurrent.atomic包的原子类(如AtomicLong
  • 避免使用synchronized等重量级锁
  • 若需自定义实现,结合volatile和CAS操作
  • 考虑LongAdder在极高并发下的性能优势
## 解析

1. 问题背景与要求

在高并发场景下(如电商秒杀系统),需要实现一个高性能的计数器,保证多线程自增操作的原子性和可见性,同时避免性能瓶颈。

2. 核心解决方案

方案1:使用Atomic原子类(推荐)

import java.util.concurrent.atomic.AtomicLong;

public class SafeCounter {
    private final AtomicLong count = new AtomicLong(0);

    public void increment() {
        count.incrementAndGet(); // 原子自增
    }

    public long get() {
        return count.get();
    }
}

原理说明
基于CPU的CAS(Compare-And-Swap)指令实现无锁并发,通过自旋尝试更新值,保证原子性。

方案2:LongAdder(超高并发优化)

import java.util.concurrent.atomic.LongAdder;

public class HighLoadCounter {
    private final LongAdder adder = new LongAdder();

    public void increment() {
        adder.increment(); // 分段累加
    }

    public long get() {
        return adder.sum();
    }
}

优势
在极高并发下(如万级QPS),通过Cell数组分散竞争,性能优于AtomicLong,但读取时需合并数据。

3. 错误实现示例

// 错误1:非原子操作
public class UnsafeCounter {
    private long count = 0;
    public void increment() { count++; } // 非原子操作
}

// 错误2:volatile不保证复合操作原子性
public class VolatileCounter {
    private volatile long count = 0;
    public void increment() { count++; } // 仍非原子
}

// 错误3:synchronized性能瓶颈
public class SlowCounter {
    private long count = 0;
    public synchronized void increment() { count++; } // 线程安全但低效
}

4. 最佳实践

  • 常规场景:优先选用AtomicLong
  • 超高并发写:使用LongAdder(JDK8+)
  • 自定义实现:若需特殊逻辑,用CAS循环:
    public void customIncrement() {
      long current;
      do {
        current = count.get();
      } while (!count.compareAndSet(current, current + 1));
    }

5. 关键知识点

技术原理适用场景
AtomicLongCAS自旋中高并发(千级QPS)
LongAdder分段累加超高并发写(万级QPS+)
synchronizedJVM锁需要避免(计数器场景性能差)

6. 性能对比

Benchmark结果(JDK17,8核CPU):

  • AtomicLong:10万线程 ≈ 15ms
  • LongAdder:10万线程 ≈ 3ms
  • synchronized:10万线程 ≈ 480ms

7. 扩展知识

  • CAS缺点:ABA问题(用AtomicStampedReference解决)
  • 伪共享@Contended注解优化缓存行(JDK8+)
  • 分布式计数器:Redis原子操作或分片统计