redisson 分布式原子操作(RAtomicLong等)

205 阅读4分钟

Redisson 提供的分布式原子操作类(如 RAtomicLongRAtomicDoubleRAtomicBoolean)基于 Redis 实现了与 Java 标准库中原子类类似的功能,确保跨节点操作的原子性。以下从原理、用法到应用场景详细说明:

一、核心原子类及原理

1. 主要原子类

  • RAtomicLong:分布式原子长整型,支持加减、比较交换等操作。
  • RAtomicDouble:分布式原子双精度浮点型。
  • RAtomicBoolean:分布式原子布尔型。
  • RAtomicReference:分布式原子引用,支持对象的原子操作。

这些类通过 Redis 的单线程特性和 Lua 脚本保证操作的原子性,避免多节点并发时的数据不一致问题。

2. 实现原理

RAtomicLong 为例:

  • 数据存储:使用 Redis 的 String 类型存储数值,键名为原子变量名。
  • 原子操作:通过 Lua 脚本实现复合操作的原子性,如自增操作对应 Redis 命令 INCRBY key delta
  • 乐观锁机制compareAndSet() 方法通过 WATCH 和事务实现 CAS(Compare-And-Swap)操作。

二、基本用法

1. RAtomicLong 示例

// 获取分布式原子长整型
RAtomicLong counter = redisson.getAtomicLong("global:counter");

// 初始化值(若不存在)
counter.compareAndSet(0, 100); // 若当前值为0,则设置为100

// 原子性自增
long newValue = counter.incrementAndGet(); // 先增后获取
long oldValue = counter.getAndIncrement(); // 先获取后增

// 原子性加减
counter.addAndGet(5);  // 加5后返回新值
counter.getAndAdd(-3); // 返回原值后减3

// 原子性比较并设置
boolean success = counter.compareAndSet(105, 200); // 若当前值为105,则设置为200

2. RAtomicBoolean 示例

// 获取分布式原子布尔型
RAtomicBoolean initialized = redisson.getAtomicBoolean("system:initialized");

// 初始化(若不存在)
initialized.compareAndSet(false, true); // 若为false,则设置为true

// 原子性获取和设置
boolean current = initialized.get();
initialized.set(true);

// 原子性比较并设置
boolean updated = initialized.compareAndSet(true, false);

3. RAtomicReference 示例

// 获取分布式原子引用
RAtomicReference<User> userRef = redisson.getAtomicReference("user:123");

// 设置值
userRef.set(new User("Alice", 25));

// 原子性比较并设置
User oldUser = new User("Alice", 25);
User newUser = new User("Alice", 26);
boolean success = userRef.compareAndSet(oldUser, newUser);

// 原子性更新(使用函数式接口)
userRef.updateAndGet(user -> {
    user.setAge(user.getAge() + 1);
    return user;
});

三、高级特性

1. 批量操作

通过 Redis 的 Lua 脚本支持多个原子操作的批量执行,减少网络开销:

// 批量执行多个原子操作(伪代码,实际需通过 Redisson 的 RScript 实现)
RScript script = redisson.getScript();
script.eval(RScript.Mode.READ_WRITE, 
    "local counter = redis.call('INCR', 'counter') " +
    "local flag = redis.call('GET', 'flag') " +
    "return {counter, flag}", 
    RScript.ReturnType.MULTI, 
    Collections.singletonList("counter"));

2. 异步操作

所有原子操作都支持异步模式,提升高并发场景下的性能:

// 异步操作示例
RFuture<Long> future = counter.incrementAndGetAsync();
future.thenAccept(value -> {
    System.out.println("异步自增后的值: " + value);
});

3. 分布式 CAS 操作

compareAndSet() 方法是实现分布式锁和乐观锁的基础:

// 分布式乐观锁示例
RAtomicLong version = redisson.getAtomicLong("data:version");

// 读取数据和版本
long currentVersion = version.get();
Data data = loadData();

// 修改数据后尝试提交
if (version.compareAndSet(currentVersion, currentVersion + 1)) {
    // 提交成功
    saveData(data);
} else {
    // 版本冲突,重试或回滚
}

四、应用场景

1. 全局唯一ID生成器

// 基于RAtomicLong实现分布式ID生成器
RAtomicLong idGenerator = redisson.getAtomicLong("global:id");

// 获取下一个唯一ID
long nextId = idGenerator.incrementAndGet();

2. 分布式计数器

// 统计网站访问量
RAtomicLong visitCounter = redisson.getAtomicLong("website:visits");

// 每次访问时增加计数
visitCounter.incrementAndGet();

// 获取总访问量
long totalVisits = visitCounter.get();

3. 分布式限流

结合原子操作和时间窗口实现简单限流:

// 每秒限流100次请求
RAtomicLong requestCounter = redisson.getAtomicLong("request:counter:" + System.currentTimeMillis() / 1000);

// 请求处理前检查
if (requestCounter.incrementAndGet() <= 100) {
    // 处理请求
} else {
    // 拒绝请求(限流)
}

4. 状态标志管理

// 控制分布式任务的启动/停止状态
RAtomicBoolean taskRunning = redisson.getAtomicBoolean("task:running");

// 启动任务前检查
if (taskRunning.compareAndSet(false, true)) {
    // 成功获取锁,启动任务
    startTask();
} else {
    // 任务已在运行
}

五、注意事项

1. 性能考虑

  • 原子操作涉及 Redis 网络通信,性能低于本地原子类(如 java.util.concurrent.atomic.AtomicLong)。
  • 高并发场景下,建议使用 updateAndGet() 等批量操作减少网络调用。

2. 异常处理

  • 网络异常可能导致操作失败,需捕获异常并重试:
    try {
        counter.incrementAndGet();
    } catch (RedisException e) {
        // 重试逻辑或降级处理
    }
    

3. 数据类型限制

  • RAtomicDouble 存储的是字符串形式的浮点数,可能存在精度损失,大额计算建议使用 RBigDecimal

4. Redis 集群兼容性

  • 在 Redis 集群模式下,需确保原子操作的键分布在同一节点(通过哈希标签),否则可能导致跨节点操作失败。

六、总结

Redisson 的分布式原子操作类提供了跨节点的原子性保证,适用于全局唯一 ID 生成、分布式计数、状态标志管理等场景。使用时需注意网络性能和异常处理,在高并发场景下可结合异步操作提升吞吐量。