news 2026/3/2 5:45:38

redis实现分布式锁

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
redis实现分布式锁

redis实现分布式锁

@ComponentpublicclassRedisDistributedLock{@AutowiredprivateRedisTemplate<String,String>redisTemplate;privatestaticfinalStringLOCK_PREFIX="lock:";privatestaticfinallongDEFAULT_EXPIRE=30_000;// 默认30秒// 加锁(带UUID防误删)publicStringtryLock(StringlockKey,longexpire){StringrequestId=UUID.randomUUID().toString();booleanresult=redisTemplate.opsForValue().setIfAbsent(LOCK_PREFIX+lockKey,requestId,expire,TimeUnit.MILLISECONDS);returnresult?requestId:null;}// 解锁(验证锁持有者身份后删除)publicbooleanunlock(StringlockKey,StringrequestId){Stringkey=LOCK_PREFIX+lockKey;StringcurrentRequestId=redisTemplate.opsForValue().get(key);if(requestId.equals(currentRequestId)){returnredisTemplate.delete(key);}returnfalse;}}

lua脚本实现方式

publicclassRedisDistributedLock{privateRedisTemplate<String,Object>redisTemplate;privateStringlockKey;privateStringlockValue;privateintexpireTime;// 获取锁的Lua脚本privatestaticfinalStringACQUIRE_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脚本privatestaticfinalStringRELEASE_LOCK_SCRIPT="if redis.call('get', KEYS[1]) == ARGV[1] then "+"return redis.call('del', KEYS[1]) "+"else "+"return 0 "+"end";publicRedisDistributedLock(RedisTemplate<String,Object>redisTemplate,StringlockKey,intexpireTime){this.redisTemplate=redisTemplate;this.lockKey=lockKey;this.expireTime=expireTime;this.lockValue=UUID.randomUUID().toString();}/** * 尝试获取分布式锁 * @return 是否获取成功 */publicbooleantryLock(){RedisScript<Long>script=newDefaultRedisScript<>(ACQUIRE_LOCK_SCRIPT,Long.class);Longresult=redisTemplate.execute(script,Collections.singletonList(lockKey),lockValue,String.valueOf(expireTime));returnresult!=null&&result==1;}/** * 释放分布式锁 * @return 是否释放成功 */publicbooleanreleaseLock(){RedisScript<Long>script=newDefaultRedisScript<>(RELEASE_LOCK_SCRIPT,Long.class);Longresult=redisTemplate.execute(script,Collections.singletonList(lockKey),lockValue);returnresult!=null&&result==1;}/** * 带超时的获取锁方法 * @param timeout 超时时间(毫秒) * @return 是否获取成功 */publicbooleantryLock(longtimeout){longstartTime=System.currentTimeMillis();do{if(tryLock()){returntrue;}try{Thread.sleep(100);// 短暂休眠避免过度竞争}catch(InterruptedExceptione){Thread.currentThread().interrupt();returnfalse;}}while(System.currentTimeMillis()-startTime<timeout);returnfalse;}}

代码说明:

  1. 使用RedisTemplate的setIfAbsent方法实现原子加锁操作
  2. 通过UUID生成唯一请求ID,防止误删其他客户端的锁
  3. 解锁时通过Lua脚本验证锁持有者身份,确保原子性
  4. 支持自定义过期时间,防止死锁
  5. 依赖Spring框架,需配置RedisTemplate Bean
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!