redis实现分布式锁

redis实现分布式锁

java 复制代码
@Component
public class RedisDistributedLock {
    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    private static final String LOCK_PREFIX = "lock:";
    private static final long DEFAULT_EXPIRE = 30_000; // 默认30秒

    // 加锁(带UUID防误删)
    public String tryLock(String lockKey, long expire) {
        String requestId = UUID.randomUUID().toString();
        boolean result = redisTemplate.opsForValue().setIfAbsent(LOCK_PREFIX + lockKey, requestId, expire, TimeUnit.MILLISECONDS);
        return result ? requestId : null;
    }

    // 解锁(验证锁持有者身份后删除)
    public boolean unlock(String lockKey, String requestId) {
        String key = LOCK_PREFIX + lockKey;
        String currentRequestId = redisTemplate.opsForValue().get(key);
        if (requestId.equals(currentRequestId)) {
            return redisTemplate.delete(key);
        }
        return false;
    }
}

lua脚本实现方式

java 复制代码
public class RedisDistributedLock {
    
    private RedisTemplate<String, Object> redisTemplate;
    private String lockKey;
    private String lockValue;
    private int expireTime;
    
    // 获取锁的Lua脚本
    private static final String ACQUIRE_LOCK_SCRIPT = 
        "if redis.call('setnx', KEYS[1], ARGV[1]) == 1 then " +
        "redis.call('expire', KEYS[1], tonumber(ARGV[2])) " +
        "return 1 " +
        "else " +
        "return 0 " +
        "end";
        
    // 释放锁的Lua脚本
    private static final String RELEASE_LOCK_SCRIPT = 
        "if redis.call('get', KEYS[1]) == ARGV[1] then " +
        "return redis.call('del', KEYS[1]) " +
        "else " +
        "return 0 " +
        "end";
    
    public RedisDistributedLock(RedisTemplate<String, Object> redisTemplate, 
                               String lockKey, int expireTime) {
        this.redisTemplate = redisTemplate;
        this.lockKey = lockKey;
        this.expireTime = expireTime;
        this.lockValue = UUID.randomUUID().toString();
    }
    
    /**
     * 尝试获取分布式锁
     * @return 是否获取成功
     */
    public boolean tryLock() {
        RedisScript<Long> script = new DefaultRedisScript<>(ACQUIRE_LOCK_SCRIPT, Long.class);
        Long result = redisTemplate.execute(script, 
                                          Collections.singletonList(lockKey), 
                                          lockValue, 
                                          String.valueOf(expireTime));
        return result != null && result == 1;
    }
    
    /**
     * 释放分布式锁
     * @return 是否释放成功
     */
    public boolean releaseLock() {
        RedisScript<Long> script = new DefaultRedisScript<>(RELEASE_LOCK_SCRIPT, Long.class);
        Long result = redisTemplate.execute(script, 
                                          Collections.singletonList(lockKey), 
                                          lockValue);
        return result != null && result == 1;
    }
    
    /**
     * 带超时的获取锁方法
     * @param timeout 超时时间(毫秒)
     * @return 是否获取成功
     */
    public boolean tryLock(long timeout) {
        long startTime = System.currentTimeMillis();
        do {
            if (tryLock()) {
                return true;
            }
            try {
                Thread.sleep(100); // 短暂休眠避免过度竞争
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                return false;
            }
        } while (System.currentTimeMillis() - startTime < timeout);
        
        return false;
    }
}

代码说明:

  1. 使用RedisTemplate的setIfAbsent方法实现原子加锁操作
  2. 通过UUID生成唯一请求ID,防止误删其他客户端的锁
  3. 解锁时通过Lua脚本验证锁持有者身份,确保原子性
  4. 支持自定义过期时间,防止死锁
  5. 依赖Spring框架,需配置RedisTemplate Bean
相关推荐
熊猫钓鱼>_>10 小时前
Redis 突发缓存穿透:一次完整的定位复盘
数据库·人工智能·redis·缓存·ai·agent·智能
脱胎换骨-军哥10 小时前
C++分布式系统设计:从通信引擎到分布式共识
开发语言·c++·分布式
Ethan010710 小时前
redis 热key问题如何解决+场景
redis
海棠Flower未眠13 小时前
SpringBoot 整合 Kafka 高性能消息队列(荣耀典藏版)
分布式·kafka
Devin~Y14 小时前
互联网大厂Java面试实战:Spring Boot、MyBatis、Redis、Kafka、JWT、Spring Cloud 与 AI 场景追问
java·spring boot·redis·spring cloud·kafka·mybatis·spring security
J-Tony1115 小时前
【Redis】数据结构&&持久化
数据结构·数据库·redis
烤代码的吐司君17 小时前
Redis 数据驱动库的供应
redis
贺国亚18 小时前
模型训练-分布式与GPU调度
分布式·wpf
刘小八18 小时前
Redis 缓存一致性:一文讲透延时双删原理、并发时序
java·数据库·redis·缓存
数行拙笔18 小时前
Redis---zset类型
数据库·redis·缓存