问题一

一个线程如果遇到业务阻塞,在业务还没有处理完的时候,超过了时间释放了锁,当业务处理完了的时候,释放锁,那么这个锁可能是别的线程的锁,那么就会引发安全问题

image-4cno.png

image-fd58.png

package com.hbue.CLASS;

import com.hbue.RedisInterface.ILock;
import org.springframework.data.redis.core.StringRedisTemplate;

import java.util.UUID;
import java.util.concurrent.TimeUnit;

public class RedisLock implements ILock {

   private  String name ;
   private StringRedisTemplate stringRedisTemplate ;


   private  final  String LOCK_PREFIX = "lock:";
   private  static  final  String ID_PREFIX = UUID.randomUUID().toString() + "-";


    public RedisLock(String name, StringRedisTemplate stringRedisTemplate) {
        this.name = name;
        this.stringRedisTemplate = stringRedisTemplate;
    }

    @Override
    public Boolean tryLock(Long lockTime) {
          //获取线程标识
        String threadName = Thread.currentThread().getName();

        Boolean isLock = stringRedisTemplate.opsForValue().setIfAbsent(LOCK_PREFIX+name, threadName , lockTime, TimeUnit.SECONDS);


        return isLock;
    }

    @Override
    public void unlock() {
        //避免redis分布式锁发生的错误
        String threadName = Thread.currentThread().getName();
        String lockName = stringRedisTemplate.opsForValue().get(LOCK_PREFIX + name);
        if (lockName != null && lockName.equals(threadName)) {
            stringRedisTemplate.delete(LOCK_PREFIX + name);
        }

    }
}

也可以在key上加上UUID

问题二

判断锁与释放锁是两个动作,中间可能会存在阻塞问题,解决方式:Lua脚本

image-9utb.png

image-ikpd.png

问题三

image-kzvm.png

image-pgqs.png

锁重入:在获取了锁之后又执行另一个方法,在另一个方法里面又获取同一把锁进行操作

image-cxhx.png

普通redis实现分布式锁是在内部维护一个String类型的结构记录锁与线程,而使用Redisson实现可重入锁是在内部维护一个Hash结构记录锁与线程及其所对应的重入次数,内部方法加锁时就将重入次数加1,当内部方法调用Unlock方法时不会删除锁而是将记录的重入次数减1,当重入次数为0时就将其删除

image-0ldf.png

image-vb9g.png