jedis setnx实现锁机制

线上接口有同用户请求的并发问题,所以准备用setnx做一个锁

为什么要用setnx:因为 Redis Setnx(SET if Not eXists) 命令是在指定的 key 不存在时,为 key 设置指定的值,所以setnx是redis的一个原子性命令

实现思路:根据用户信息生成一个key,放缓存待 接口执行完毕之后,删除该缓存,下次同用户请求进来,如果未执行完毕则缓存还存在,放缓存失败则返回对应提示信息,接口停止继续执行

上代码:

    @Autowired(required = false)
    private Pool<Jedis> poolJedis;


   /**
     * 添加锁 防并发 此方法添加锁未设置过期时间,需手动释放
     *
     * @param key key
     * @param seconds 缓存过期时间
     * @return boolean
     */
    public boolean tryLock(String key,int seconds) {
        if (Validator.isNullOrEmpty(poolJedis)) {
            return false;
        }
        try (Jedis jedisCluster = poolJedis.getResource()) {
            // 在指定的 key 不存在时,为 key 设置指定的值。
            // 根据以下第三个nxxx参数,把key、value set到redis中
            // NX : not exists, 只有key 不存在时才把key value set 到redis
            // XX : is  exists, 只有key 存在时才把key value set 到redis
            // 第四个expx参数有两个值可选 :
            // EX : seconds 秒
            // PX :  milliseconds 毫秒
            String nx = jedisCluster.set(key, "value", "NX", "EX", seconds);
            if (Validator.isNotNullOrEmpty(nx) && "OK".equals(nx)) {
                return true;
            }
        } catch (Exception e) {
            LOGGER.error("addLock error:", e);
        }
        return false;
    }



   /**
     * 释放锁
     *
     * @param key key
     */
    public void clearLock(String key) {
        Jedis jedisCluster = null;
        try {
            jedisCluster = pool.getResource();
            Long a = jedisCluster .del(key);
        } catch (Exception e) {
            LOGGER.error("", e);
            //线程休眠1秒
            try {
                Thread.sleep(1000);
                removeLock(key);
            } catch (InterruptedException e1) {
                LOGGER.error("removeLock error:", e1);
                Thread.currentThread().interrupt();
            } finally {
                if (jedisCluster != null) {
                    jedisCluster .close();
                }
            }
        }
    }

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Redis是一个基于内存的数据存储系统,它提供了多种类型的数据结构,其中包括了分布式锁。使用Redis实现分布式锁可以避免多个线程同时修改同一个资源的问题,从而提高程序的并发性和性能表现。 在Java中使用Redis实现分布式锁的demo可以分为以下几个步骤: 1. 连接Redis:使用Java Redis客户端连接Redis服务器。 2. 获取锁:利用RedisSET命令实现原子操作,如果返回值为成功,则获取到了锁。 3. 执行业务逻辑:执行需要加锁的代码块。 4. 释放锁:利用Lua的脚本语言实现解锁操作,释放锁。 下面是示例代码: ``` public class RedisLockDemo { private static final int LOCK_EXPIRE_TIME = 5000; //锁过期时间 private RedisTemplate<String, Object> redisTemplate; // Redis 客户端 private String lockKey = "test_lock"; // 锁 key private String lockValue = System.currentTimeMillis() + Thread.currentThread().getName(); // 锁 value(当前时间 + 线程名) /** * 获取锁 * * @return 成功获取锁返回 true,未成功获取锁返回 false */ public boolean lock() { Boolean result = redisTemplate.opsForValue().setIfAbsent(lockKey, lockValue, Duration.ofMillis(LOCK_EXPIRE_TIME)); return result != null && result; } /** * 释放锁 * * @return 成功释放返回 true,未成功释放返回 false */ public boolean unlock() { DefaultRedisScript<Long> script = new DefaultRedisScript<>(); script.setScriptSource(new ResourceScriptSource(new ClassPathResource("unlock.lua"))); script.setResultType(Long.class); Long result = redisTemplate.execute(script, Collections.singletonList(lockKey), lockValue); return result != null && result == 1L; } /** * 执行业务逻辑 */ public void doBusiness() { //开始处理业务逻辑 try { Thread.sleep(1000); System.out.println("正在执行业务逻辑……"); } catch (InterruptedException e) { e.printStackTrace(); } //业务逻辑处理完成 System.out.println("业务逻辑处理完成。"); } } ``` 上述代码中,我们定义了 RedisLockDemo 类,其中包含了三个方法,lock()、unlock() 和 doBusiness()。 其中 lock() 方法用于获取锁,内部调用了 Jedisset() 方法实现锁的加锁操作。我们采用原子操作,即采用 RedisSETNX 命令来实现锁的加锁操作。如果 SETNX 命令返回了1,则说明此时获取到了锁;反之,则说明锁已被其他线程占用。 unlock() 方法用于释放锁,内部采用 Lua 语言来实现解锁操作。我们采用 Lua 脚本的方式来避免释放其他线程持有的锁,有效保证分布式锁的唯一性。 doBusiness() 方法用于执行业务逻辑,在获取到锁之后即可执行,特别需要注意的是,由于获得了锁的并非只有当前线程,所以需要加入重试策略,如果失败重新请求锁。 综上所述,通过上述代码演示,我们可以在Java应用中使用Redis实现分布式锁机制,从而提高程序的并发性和性能表现。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值