秒杀系统不超卖:Redisson分布式计数器AtomicLong与AtomicDouble实战指南

秒杀系统不超卖:Redisson分布式计数器AtomicLong与AtomicDouble实战指南

【免费下载链接】redisson 【免费下载链接】redisson 项目地址: https://gitcode.com/gh_mirrors/red/redisson

你是否还在为分布式系统中的并发计数问题头疼?库存超卖、统计数据不一致、分布式ID生成错误——这些问题往往源于传统单机计数器无法跨节点同步状态。本文将通过Redisson的分布式原子类AtomicLong和AtomicDouble,带你一站式解决分布式环境下的计数难题,掌握高并发场景下的精准计数方案。

分布式计数的痛点与解决方案

在分布式系统中,多个服务实例同时操作同一个计数器时,传统的java.util.concurrent.atomic.AtomicLong由于仅作用于单个JVM进程,无法保证跨节点的数据一致性。以电商秒杀场景为例,当100个用户同时抢购最后10件商品时,若每个服务实例单独维护库存计数,会导致超卖问题。

Redisson提供的分布式原子类通过Redis的单线程特性和Lua脚本原子性操作,完美解决了这一问题。其核心实现位于:

快速上手:Redisson环境搭建

Maven依赖配置

在项目的pom.xml中添加Redisson依赖:

<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson</artifactId>
    <version>3.30.0</version>
</dependency>

初始化Redisson客户端

通过简单配置即可创建Redisson客户端实例,支持单机、集群、哨兵等多种部署模式:

// [Redisson.java](https://link.gitcode.com/i/1b7cf85cb3557c8ae3ce2f7ec229e318)
Config config = new Config();
config.useSingleServer()
      .setAddress("redis://127.0.0.1:6379");
RedissonClient redisson = Redisson.create(config);

RAtomicLong核心操作与实战场景

基础API全解析

RedissonAtomicLong实现了与JDK AtomicLong类似的API,同时提供异步操作能力:

方法同步调用异步调用说明
递增并获取incrementAndGet()incrementAndGetAsync()原子性+1并返回新值
递减并获取decrementAndGet()decrementAndGetAsync()原子性-1并返回新值
累加并获取addAndGet(long delta)addAndGetAsync(long delta)原子性增加delta并返回新值
比较并设置compareAndSet(long expect, long update)compareAndSetAsync(...)CAS操作,成功返回true

秒杀系统库存控制案例

以下代码展示如何使用RAtomicLong实现秒杀场景的库存控制:

// 获取分布式原子计数器实例
RAtomicLong stockCounter = redisson.getAtomicLong("seckill:stock:1001");
// 初始化库存为100件
stockCounter.set(100);

// 用户抢购逻辑
public boolean purchase(String userId) {
    // 原子性递减库存,返回新值
    long remaining = stockCounter.decrementAndGet();
    if (remaining < 0) {
        // 库存不足,恢复计数
        stockCounter.incrementAndGet();
        return false;
    }
    // 生成订单逻辑...
    return true;
}

分布式ID生成器实现

利用RAtomicLong的递增特性,可以轻松实现分布式环境下的唯一ID生成:

RAtomicLong idGenerator = redisson.getAtomicLong("order:id:generator");
// 初始值设为10000
idGenerator.set(10000);

// 生成唯一订单号
public long generateOrderId() {
    return idGenerator.incrementAndGet();
}

RAtomicDouble与浮点型计数场景

对于需要小数精度的计数场景(如评分系统、统计平均值),RAtomicDouble提供了双精度浮点型支持。其核心实现通过Redis的字符串存储,使用Lua脚本保证操作原子性。

核心方法示例

// 获取分布式浮点计数器
RAtomicDouble scoreCounter = redisson.getAtomicDouble("product:score:1001");
// 设置初始评分
scoreCounter.set(4.5);

// 增加0.3分并获取新值
double newScore = scoreCounter.addAndGet(0.3);
// 输出: 4.8
System.out.println(newScore);

// 比较并设置新值
boolean success = scoreCounter.compareAndSet(4.8, 4.7);

商品评分统计案例

以下代码实现电商商品的平均分统计功能:

public class ProductScoreService {
    private final RAtomicDouble avgScore;
    private final RAtomicLong scoreCount;
    
    public ProductScoreService(RedissonClient redisson, String productId) {
        this.avgScore = redisson.getAtomicDouble("product:avgScore:" + productId);
        this.scoreCount = redisson.getAtomicLong("product:scoreCount:" + productId);
    }
    
    public void addScore(double score) {
        // 原子性更新总分和计数
        double total = avgScore.get() * scoreCount.get();
        avgScore.set((total + score) / scoreCount.incrementAndGet());
    }
    
    public double getAvgScore() {
        return avgScore.get();
    }
}

高级特性:监听器与原子操作扩展

计数器变更监听器

Redisson提供了事件监听机制,可以实时响应计数器变化:

RAtomicLong counter = redisson.getAtomicLong("user:login:counter");
// 添加递增监听器
counter.addListener((IncrByListener) (charSequence, long1) -> {
    System.out.println("计数器递增: " + long1);
});

批量原子操作

通过Redisson的getAtomicLonggetAtomicDouble方法,可以轻松创建多个计数器实例,实现复杂业务场景的原子操作组合:

// [Redisson.java](https://link.gitcode.com/i/1b7cf85cb3557c8ae3ce2f7ec229e318)
RAtomicLong orderCounter = redisson.getAtomicLong("daily:order:count");
RAtomicDouble salesAmount = redisson.getAtomicDouble("daily:sales:amount");

// 订单创建时原子更新两个计数器
public void createOrder(double amount) {
    orderCounter.incrementAndGet();
    salesAmount.addAndGet(amount);
}

性能优化与最佳实践

合理选择数据类型

  • 整数计数优先使用RAtomicLong,存储和计算效率更高
  • 小数计数(如评分、百分比)使用RAtomicDouble,避免浮点运算误差

避免热点Key问题

对于高并发场景,可通过Redisson的分片机制分散热点:

// [RedissonLongAdder.java](https://link.gitcode.com/i/e27e41b4b4af9c8a96c5b3a3daf8bc12)
RLongAdder counter = redisson.getLongAdder("high:concurrency:counter");
counter.increment();

资源释放

使用完毕后,及时关闭Redisson客户端释放资源:

// [Redisson.java](https://link.gitcode.com/i/1b7cf85cb3557c8ae3ce2f7ec229e318)
redisson.shutdown();

总结与扩展阅读

通过Redisson的分布式原子类,我们可以在分布式环境中轻松实现线程安全的计数功能。无论是秒杀库存控制、分布式ID生成,还是实时统计分析,RAtomicLong和RAtomicDouble都能提供高效可靠的原子操作支持。

相关模块与文档

下期预告

下一篇我们将深入探讨Redisson的分布式集合框架,学习如何使用分布式Map、Set等数据结构解决更复杂的业务场景。记得点赞收藏本文,关注获取更多分布式系统实践指南!

【免费下载链接】redisson 【免费下载链接】redisson 项目地址: https://gitcode.com/gh_mirrors/red/redisson

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值