Skip to content

Redis 分布式锁

TIP

分布式锁是控制分布式系统并发访问共享资源的手段。Redis 基于 SETNX 和 Lua 脚本可以实现可靠的分布式锁。

基本实现

java
// 加锁
public boolean lock(String key, String value, long expireSeconds) {
    // NX: 不存在时才设置
    // EX: 设置过期时间
    return redis.call("SET", key, value, "NX", "EX", expireSeconds);
}

// 解锁(使用 Lua 保证原子性)
public boolean unlock(String key, String value) {
    String script = "if redis.call('GET', KEYS[1]) == ARGV[1] " +
                    "then return redis.call('DEL', KEYS[1]) " +
                    "else return 0 end";
    return redis.call("EVAL", script, 1, key, value);
}

Redisson 框架

实际开发中使用 Redisson 封装好的锁:

java
// 1. 引入依赖
// implementation 'org.redisson:redisson-spring-boot-starter:3.20.0'

// 2. 使用 RedissonClient
@Autowired
private RedissonClient redisson;

public void businessMethod() {
    RLock lock = redisson.getLock("order:" + orderId);
    try {
        // 尝试加锁,最多等待100秒
        if (lock.tryLock(100, 10, TimeUnit.SECONDS)) {
            // 业务逻辑
        }
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
    } finally {
        if (lock.isHeldByCurrentThread()) {
            lock.unlock();
        }
    }
}

可重入锁

java
// Redisson 的可重入锁
RLock lock = redisson.getLock("myLock");

// 同一个线程可多次获取锁
lock.lock();
lock.lock(); // 可重入

// 业务代码
lock.unlock();
lock.unlock(); // 释放两次

公平锁 / 读写锁

java
// 公平锁 — 按请求顺序获取
RLock fairLock = redisson.getFairLock("fairLock");

// 读写锁
RReadWriteLock rwLock = redisson.getReadWriteLock("rwLock");
RLock readLock = rwLock.readLock();
RLock writeLock = rwLock.writeLock();

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

WARNING

实现分布式锁需要关注:

  • 原子性:加锁和设置过期时间要原子操作
  • 防死锁:必须设置过期时间
  • 防误删:只能删除自己的锁(通过 value 标识)
  • 可重入:同一线程可重复获取