Redis中setnx的使用


前言

在使用Redis的过程中遇到的一些问题记录。


set命令的其他参数

SET命令可用选项的基本语法
SET KEY VALUE [EX seconds] [PX milliseconds] [NX|XX]
可选参数如下:

  • ex : 到期时间(以秒为单位)
  • px : 到期时间(以毫秒为单位)
  • nx : 仅在键不存在时设置键
  • xx : 只有在键已存在时才设置

示例

SET mykey “redis” EX 60 NX
在键“mykey”不存在时,设置键的值为“redis”,到期时间为60秒。

setnx概念

setnx是「SET if Not eXists」的缩写,只有不存在的时候才设置,可以利用它来实现锁的效果。

SETNX key value

若给定的 key 已经存在,则 setnx不做任何动作。

使用redisTemplate操作setnx

    @Override
    public boolean setNx(String key,String value, long time) {
        try {
            RedisCallback<String> callback = (connection) -> {
                JedisCommands commands = (JedisCommands) connection.getNativeConnection();
                return commands.set(key, value, "NX", "PX", time);
            };
            String result = redisTemplate.execute(callback);
            return !StringUtils.isEmpty(result);
        } catch (Exception e) {
            logger.error("set redis occured an exception", e);
        }
        return false;
    }

作用

分布式锁

向Redis添加一个key,添加成功代表获取到锁,添加失败则代表没有获取到锁。只要保证多个线程使用的是同一个key,它们添加时就只会有一个线程添加成功获取到锁。而释放锁时只需要将锁删除即可。

可能遇到的问题

死锁

如果前一个线程由于某种原因获取到锁后未正常释放,后面的线程获取不到锁无法往下继续执行,就会形成死锁的现象。

解决方案

设置锁的过期时间。
由上面提到的EX或者PX即可设置setnxkey的过期时间。

误删锁

在设置了过期时间后,可能会出现这样的现象:
线程1在自己的锁过期后才从沉睡中苏醒,且想要执行释放锁操作。而此时实际的锁归线程2所有,因此线程1释放的锁实际是线程2的锁,且线程2并不知情。
当线程2想释放锁时,线程3可能已经获取到了被线程1释放的锁,导致线程2释放的锁实际是线程3的锁。
以此类推每一个线程释放的都是下一个线程的锁,直到最后一个线程无锁可删。
这种误删锁的情况让锁的存在意义荡然无存,本来应该串行执行的线程,在一定程度上都开始并发执行了。

解决方案

给锁加上线程标识。
在添加key的时候,key的value存储当前线程的唯一标识。在删除锁的时候,将线程标识取出来进行判断,如果相同就表示锁是自己的能够删除,否则不能删除。
判断锁能否删除的操作和删除锁的操作要作为一个整体执行,保证锁删除的原子性,避免线程1判断锁后锁被线程2获取,仍然会导致线程1误删线程2的锁的问题。

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值