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;}}代码说明:
- 使用RedisTemplate的setIfAbsent方法实现原子加锁操作
- 通过UUID生成唯一请求ID,防止误删其他客户端的锁
- 解锁时通过Lua脚本验证锁持有者身份,确保原子性
- 支持自定义过期时间,防止死锁
- 依赖Spring框架,需配置RedisTemplate Bean