Java分布式数据锁API怎么Redisson

wen java案例 17

本文目录导读:

Java分布式数据锁API怎么Redisson

  1. Redisson 分布式锁的核心优势
  2. Maven 依赖
  3. 基本使用流程
  4. 核心 API 详解
  5. 可重入锁特性
  6. 公平锁(Fair Lock)
  7. 读写锁(ReadWriteLock)
  8. 红锁(RedLock)
  9. 异步/响应式 API
  10. 完整示例:秒杀场景
  11. 十一、常见问题与注意事项

Redisson 是一个基于 Redis 的 Java 分布式数据锁解决方案,它提供了丰富且易用的分布式锁 API,下面从核心概念、常用 API 到高级特性为你详细讲解。


Redisson 分布式锁的核心优势

相比手动实现 Redis SETNX 或使用 Jedis/Lettuce 原生客户端,Redisson 提供了:

  • 自动续期:WatchDog 机制防止锁过期导致业务未完成
  • 可重入:同一个线程可多次获取同一把锁
  • 公平锁:按请求顺序获取锁
  • 读写锁:读读不互斥,读写/写写互斥
  • 红锁(RedLock):跨多个 Redis 实例的高可用锁
  • 异步/响应式 API:支持 Reactive/RxJava

Maven 依赖

<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson</artifactId>
    <version>3.27.2</version>  <!-- 更新到最新稳定版 -->
</dependency>

基本使用流程

创建 Redisson 客户端

// 单节点模式
Config config = new Config();
config.useSingleServer()
      .setAddress("redis://127.0.0.1:6379")
      .setPassword("yourPassword");  // 如果设置了密码
RedissonClient redisson = Redisson.create(config);

其他模式(哨兵、集群、主从)配置方式类似。

获取锁并操作

// 获取锁对象(参数为锁的 key 名称)
RLock lock = redisson.getLock("myLock");
try {
    // 1. 最常见:阻塞等待获取锁,默认锁持有时间 30 秒
    lock.lock();
    // 2. 也可手动指定持有时间(单位:秒)
    // lock.lock(10, TimeUnit.SECONDS);
    // 3. 尝试获取锁,等待 3 秒,持有 10 秒
    // boolean acquired = lock.tryLock(3, 10, TimeUnit.SECONDS);
    // if (!acquired) {
    //     throw new RuntimeException("获取锁失败");
    // }
    // 执行业务逻辑
    doBusiness();
} finally {
    // 务必要释放锁
    lock.unlock();
}

核心 API 详解

lock() / lock(leaseTime, timeUnit)

方法 说明
lock() 阻塞等待直到获取锁,默认 leaseTime = 30 秒,WatchDog 自动续期
lock(leaseTime, timeUnit) 指定锁的持有时间,到期自动释放(无 WatchDog)

WatchDog 机制

  • 当使用无参 lock() 时,Redisson 启动后台线程
  • 每 10 秒检查一次锁,如果业务还在执行(线程存活),则重置锁过期时间为 30 秒
  • 有效防止业务时间 > 锁过期时间导致的误释放

tryLock(waitTime, leaseTime, timeUnit)

boolean tryLock(long waitTime, long leaseTime, TimeUnit unit) throws InterruptedException;
  • waitTime:等待获取锁的最长时间
  • leaseTime:锁的持有时间(-1 表示使用 WatchDog 自动续期)

返回 true 表示获取成功,false 表示超时未获取到。

unlock()

释放锁。必须在 finally 块中调用,否则会造成死锁。

判断锁状态

boolean isLocked = lock.isLocked();      // 锁是否被任何线程持有
boolean heldByCurrentThread = lock.isHeldByCurrentThread();  // 是否被当前线程持有
long holdCount = lock.getHoldCount();    // 当前线程持有该锁的次数(用于可重入锁)

可重入锁特性

Redisson 的 RLock 默认就是可重入的:

RLock lock = redisson.getLock("myLock");
lock.lock();
// 重入获取
lock.lock();
lock.lock();
// 需要释放相同次数
lock.unlock();
lock.unlock();
lock.unlock();

公平锁(Fair Lock)

保证锁的获取顺序与请求顺序一致(FIFO):

// 注意方法名是 getFairLock,不是 getLock
RLock fairLock = redisson.getFairLock("fairLock");
// 使用方式与普通锁完全一致
fairLock.lock();
try {
    // 业务逻辑
} finally {
    fairLock.unlock();
}

读写锁(ReadWriteLock)

读读不互斥,读写/写写互斥:

RReadWriteLock rwLock = redisson.getReadWriteLock("myRWLock");
RLock readLock = rwLock.readLock();
RLock writeLock = rwLock.writeLock();
// 读锁 - 多个线程可以同时持有
readLock.lock();
try {
    // 读取共享数据
} finally {
    readLock.unlock();
}
// 写锁 - 需要等待所有读锁和写锁释放
writeLock.lock();
try {
    // 写入共享数据
} finally {
    writeLock.unlock();
}

红锁(RedLock)

用于多 Redis 主节点的高可用场景:

// 需要配置多个独立的 Redis 主节点
Config config1 = new Config();
config1.useSingleServer().setAddress("redis://redis1:6379");
Config config2 = new Config();
config2.useSingleServer().setAddress("redis://redis2:6379");
Config config3 = new Config();
config3.useSingleServer().setAddress("redis://redis3:6379");
// 创建红锁
RedissonRedLock redLock = new RedissonRedLock(
    Redisson.create(config1).getLock("lock1"),
    Redisson.create(config2).getLock("lock2"),
    Redisson.create(config3).getLock("lock3")
);
redLock.lock();
try {
    // 业务逻辑(超过半数节点加锁成功才算成功)
} finally {
    redLock.unlock();
}

异步/响应式 API

Redisson 支持异步无阻塞调用:

// 异步锁
RLockAsync lockAsync = redisson.getLock("asyncLock");
RFuture<Void> future = lockAsync.lockAsync();
future.whenComplete((res, ex) -> {
    if (ex == null) {
        // 获取锁成功
        lockAsync.unlockAsync();
    }
});
// 响应式锁(需要引入 spring-boot-starter-webflux 等)
RReactiveLock reactiveLock = redisson.getReactiveLock("reactiveLock");
Mono<Void> lockMono = reactiveLock.lock();

完整示例:秒杀场景

@Service
public class SeckillService {
    @Autowired
    private RedissonClient redisson;
    public boolean seckill(Long userId, Long productId) {
        String lockKey = "seckill:lock:" + productId;
        RLock lock = redisson.getLock(lockKey);
        try {
            // 最多等待 2 秒,拿到锁后持有 5 秒(WatchDog 自动续期)
            if (lock.tryLock(2, -1, TimeUnit.SECONDS)) {
                // 查询库存
                int stock = queryStock(productId);
                if (stock > 0) {
                    // 扣减库存
                    reduceStock(productId);
                    // 创建订单
                    createOrder(userId, productId);
                    return true;
                } else {
                    return false;
                }
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new RuntimeException("获取锁被中断", e);
        } finally {
            // 如果当前线程持有锁才释放
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
        return false;
    }
}

十一、常见问题与注意事项

WatchDog 何时启动?

  • 调用 lock() 无参时启动
  • 调用 lock(leaseTime, unit)leaseTime = -1 时启动
  • 调用 tryLock(waitTime, leaseTime, unit)leaseTime = -1 时启动

锁超时 vs 业务超时

如果业务执行时间超出预期:

  • 使用 WatchDog:自动续期,无需担心
  • 自定义 leaseTime:到期自动释放,即使业务未完成

建议:不确定业务耗时用 WatchDog;明确知道最大耗时用固定 leaseTime。

性能调优

// 通过配置调整 WatchDog 检查间隔(默认 10 秒)
config.setLockWatchdogTimeout(5000);  // 改为 5 秒

锁的粒度控制

  • 粗粒度:一个锁保护所有数据 → 性能差
  • 细粒度:每个数据一个锁(如 lock:user:123) → 性能好,但锁数量多

建议:根据热点数据设计,避免单个锁成为瓶颈。


Redisson 的分布式锁 API 设计直观,覆盖了大部分企业级场景:

场景 推荐方案
基本互斥 getLock() + lock()
需设置超时 tryLock(waitTime, leaseTime, unit)
防止业务超期 无参 lock() 利用 WatchDog
按序获取 getFairLock()
读多写少 getReadWriteLock()
跨 Redis 高可用 RedissonRedLock
高并发非阻塞 异步/响应式 API

掌握这些 API,你可以轻松应对大部分分布式锁需求,如果需要更高级的自定义(如多重锁、联锁),Redisson 也提供了 RedissonMultiLock 等组合 API。

抱歉,评论功能暂时关闭!