栏目分类:
子分类:
返回
终身学习网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
终身学习网 > IT > 软件开发 > 后端开发 > Java

redis分布式锁问题分析与解决Demo

Java 更新时间:发布时间: 百科书网 趣学号

@Service
public class baseBrandServiceImpl extends ServiceImpl implements baseBrandService {
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private RedissonClient redissonClient;


    public void setNum0() {
        String value = (String)redisTemplate.opsForValue().get("num");
        if(StringUtils.isEmpty(value)){
            redisTemplate.opsForValue().set("num","1");
        }else{
            int num = Integer.parseInt(value);
            //对num加1操作然后放入redis当中
            redisTemplate.opsForValue().set("num",String.valueOf(++num));
        }
    }
    //@Override
    public synchronized void setNum01() {
        String value = (String)redisTemplate.opsForValue().get("num");
        if(StringUtils.isEmpty(value)){
            redisTemplate.opsForValue().set("num","1");
        }else{
            int num = Integer.parseInt(value);
            //对num加1操作然后放入redis当中
            redisTemplate.opsForValue().set("num",String.valueOf(++num));
        }
    }
    private void doBusiness() {
        String value = (String) redisTemplate.opsForValue().get("num");
        if (StringUtils.isEmpty(value)) {
            redisTemplate.opsForValue().set("num", "1");
        } else {
            int num = Integer.parseInt(value);
            //对num加1操作然后放入redis当中
            redisTemplate.opsForValue().set("num", String.valueOf(++num));
        }
    }


    //分布式锁 方案一  缺点:if逻辑中若抛了异常,无法释放锁
    public void setNum1() {
        //如果往redis里面设置值成功代表获取到了锁
        boolean acquireLock = redisTemplate.opsForValue().setIfAbsent("lock", "ok");
        if(acquireLock){
            //如果这里出现异常 锁无法释放 会一直占用
            doBusiness();
            //★执行完业务逻辑之后删除锁,否则其他线程拿不到释放后的锁了
            redisTemplate.delete("lock");
        }else{
            //设置睡眠时间
            SleepUtils.sleepMillis(50);
            //自旋
            setNum();
        }
    }
    //分布式锁 方案二 缺点:锁过期时间和业务处理时间不一致,导致删除其他线程的锁
    public void setNum2() {
        //如果往redis里面设置值成功代表获取到了锁  到期之后自动释放锁 但是此时有可能会把其他线程的锁给删掉
        boolean acquireLock = redisTemplate.opsForValue().setIfAbsent("lock", "ok",3, TimeUnit.SECONDS);
        if(acquireLock){
            doBusiness();
            //执行完业务逻辑之后删除锁
            redisTemplate.delete("lock");
        }else{
            //设置睡眠时间
            SleepUtils.sleepMillis(50);
            //自旋
            setNum();
        }
    }
    //分布式锁 方案三 缺点:删除锁的操作不具备原子性,不保证判断和删除所操作同时执行成功/失败(原子性)

    public void setNum3() {
        //加锁的值信息
        String uuid = UUID.randomUUID().toString();
        //如果往redis里面设置值成功代表获取到了锁
        boolean acquireLock = redisTemplate.opsForValue().setIfAbsent("lock", uuid,3, TimeUnit.SECONDS);
        if(acquireLock){
            doBusiness();
            //删除之前判定是否为该线程的锁  存在的问题在于下面的判断和删除不具备原子性
            String redisUuid = (String)redisTemplate.opsForValue().get("lock");
            if(uuid.equals(redisUuid)){
                //执行完业务逻辑之后删除锁
                redisTemplate.delete("lock");
            }
        }else{
            //设置睡眠时间
            SleepUtils.sleepMillis(50);
            //自旋
            setNum();
        }
    }

    //分布式锁 方案四 lua 缺点:集群下依旧有安全问题,拿不同线程的锁
    public void setNum4() {
        //加锁的值信息
        String uuid = UUID.randomUUID().toString();
        //如果往redis里面设置值成功代表获取到了锁
        boolean acquireLock = redisTemplate.opsForValue().setIfAbsent("lock", uuid,3, TimeUnit.SECONDS);
        if(acquireLock){
            doBusiness();
            //定义一个lua脚本
            String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
            DefaultRedisscript redisscript = new DefaultRedisscript<>();
            //把上面的script代码放到redisscript对象中
            redisscript.setscriptText(script);
            //设置执行脚本之后返回值是什么类型
            redisscript.setResultType(Long.class);
            //准备执行lua脚本
            redisTemplate.execute(redisscript, Arrays.asList("lock"),uuid);
            
        }else{
            //设置睡眠时间
            SleepUtils.sleepMillis(50);
            //自旋
            setNum();
        }
    }
    //redissonClient方式一
    //@Override
    public void setNum11() {
        RLock lock = redissonClient.getLock("lock");
        lock.lock();
        doBusiness();
        lock.unlock();
    }
    //redissonClient方式二
    //@Override
    public void setNum22() {
        RLock lock = redissonClient.getLock("lock");
        //加锁以后3秒之后自动释放 无需调用unlock
        lock.lock(3, TimeUnit.SECONDS);
        doBusiness();
        lock.unlock();
    }
    //★★★最终方案:redissonClient方式三
    @Override
    public void setNum() {
        RLock lock = redissonClient.getLock("lock");
        try {
            
            boolean acquireLock = lock.tryLock(100, 3, TimeUnit.SECONDS);
            if(acquireLock){
                doBusiness();
            }else{
                //设置睡眠时间
                SleepUtils.sleepMillis(50);
                //自旋
                setNum();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
}
转载请注明:文章转载自 www.051e.com
本文地址:http://www.051e.com/it/294920.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 ©2023-2025 051e.com

ICP备案号:京ICP备12030808号