> 文档中心 > Redis分布式锁(仅供参考)

Redis分布式锁(仅供参考)


redis命令参考

使用场景:存在多个线程同一时刻操作同一个数据

@Componentpublic class RedisLock {private static final Logger log = LoggerFactory.getLogger(RedisLock.class);/ * 锁默认持有时间 */static final int DEFAULT_EXPIRE = 5;/ * 锁前缀 */static String LOCK_PREFIX = "DCS_LOCK_";/ * lua脚本     * 通过get请求获取到值,判断是否与传入的值的是否一致     * 如果一致则执行del请求并返回结果     * 不一致返回0 */static final String RELEASE_LOCK_LUA_SCRIPT = "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";/ * 释放锁成功返回值 */static final Long RELEASE_LOCK_SUCCESS_RESULT = 1L;@Resourceprivate RedisTemplate redisTemplate;/ * 加锁 自旋五次 * * @param redisLockDto 锁实体 * @return 是否加锁成功 */@SuppressWarnings("all")public boolean lock(RedisLockDto redisLockDto) {boolean locked = false;// 锁自旋次数int tryCount = 5;while (!locked&& tryCount > 0) {    /     *setIfAbsent方法底层相当于执行redis的setnx命令 */locked = redisTemplate.opsForValue().setIfAbsent(LOCK_PREFIX + redisLockDto.getLockKey(),redisLockDto.getRequestId(),redisLockDto.getExpire() == null ? DEFAULT_EXPIRE : redisLockDto.getExpire(),TimeUnit.SECONDS);tryCount--;try {Thread.sleep(200);} catch (InterruptedException e) {log.error("线程被中断" + Thread.currentThread().getId(), e);}}return locked;}/ * lua脚本解锁 不会解别人的锁 * * @param redisLockDto 锁实体 * @return 是否解锁成功 */public boolean unLockLua(RedisLockDto redisLockDto) {if (redisLockDto == null || redisLockDto.getLockKey() == null || redisLockDto.getRequestId() == null) {return false;}log.info("release lock:{key:{},clientId:{}}", redisLockDto.getLockKey(), redisLockDto.getRequestId());// lua脚本DefaultRedisScript redisScript = new DefaultRedisScript(RELEASE_LOCK_LUA_SCRIPT, Long.class);String key = LOCK_PREFIX + redisLockDto.getLockKey(); /  * 三个参数   * script:lua脚本    * keys:key集合  * args:key对应的value(需要与key的顺序保持一致)  */Long result = redisTemplate.execute(redisScript, Collections.singletonList(key), redisLockDto.getRequestId());return ObjectUtil.equals(result, RELEASE_LOCK_SUCCESS_RESULT);}

RedisLockDto 

public class RedisLockDto implements Serializable {/ * 锁名称 */private String lockKey;/ * 请求方id 一般为UUID */private String requestId;/ * 超时时间 */private Integer expire;public String getLockKey() {return lockKey;}public RedisLockDto setLockKey(String lockKey) {this.lockKey = lockKey;return this;}public String getRequestId() {return requestId;}public RedisLockDto setRequestId(String requestId) {this.requestId = requestId;return this;}public Integer getExpire() {return expire;}public RedisLockDto setExpire(Integer expire) {this.expire = expire;return this;}}

存在问题:线程A在超时时间之内没有处理完相关业务,这是B可以获取到锁。

解决方案:考虑让获得锁的线程开启一个守护线程给快要过期但是业务还没处理完的锁续命

Redis分布式锁(仅供参考) 创作打卡挑战赛 Redis分布式锁(仅供参考) 赢取流量/现金/CSDN周边激励大奖