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
相关推荐
汽车仪器仪表相关领域42 分钟前
KRYPTON坚固型IP67 EtherCAT总线数据采集模块:工业级分布式采集方案
分布式·功能测试·汽车·压力测试·可用性测试
Rain的Java大神之路1 小时前
线上接口负载满了如何解决
java·数据库·redis·后端·缓存·面试·架构
霸道流氓气质3 小时前
Java中信号量(Semaphore):从本地到分布式
java·开发语言·分布式
Amir_zy4 小时前
Redis测试方法全攻略:冒烟、压测与稳定性验证
redis·压力测试
naierfengdian4 小时前
分布式风电助力乡村能源转型的技术路径
分布式·能源
霸道流氓气质5 小时前
RedLock:Redis 分布式锁的高可用方案
数据库·redis·分布式
hhzz5 小时前
《深度学习框架PyTorch入门与实践》系列:09-分布式与并行训练之DataParallel、DDP与Horovod
pytorch·分布式·深度学习
breeze jiang6 小时前
Next.js App Router 父子组件 RSC 拆分实战:从 Redis Hash 到客户端交互的最小化边界
javascript·redis·哈希算法
晚染烟16 小时前
每日八股day17
redis
城管不管21 小时前
重生——第九次面试2026.8.13某车一面
分布式·ai·面试·职场和发展·rabbitmq