redisTemplate通过setNx实现分布式锁

  • 客户端C2使用SETNX命令获取锁
  • 假设客户端C1已经崩溃但是仍然持有锁,所以Redis返回false给客户端C2
  • 客户端C2使用GET命令获取锁并检查锁是否已经过期,如果没有过期,则继续等待一段时间并重新重试
  • 如果锁已经过期,客户端C2尝试 GETSET lock.name <current Unix timestamp + lock timeout + 1>
  • 利用GETSET语法,客户端C2可以检查key的旧值(锁的旧时间)是否仍然是过期时间,如果是,则获取锁
  • 如果另一个客户端C3率先获取到锁,客户端C2执行GETSET命令后将返回非过期时间,然后客户端C2继续从头开始重新尝试获取锁。此操作客户端C2将会延长一点客户端C3获取到的锁的过期时间,不过这不是什么大问题。
 /**
     * 获取一个redis分布锁
     *
     * @param lockKey        锁住的key
     * @param lockExpireMils 锁住的时长。如果超时未解锁,视为加锁线程死亡,其他线程可夺取锁
     * @return
     */
    public boolean lock(String lockKey, long lockExpireMils) {
        return (Boolean) redisTemplate.execute((RedisCallback) connection -> {
            long nowTime = System.currentTimeMillis();
            Boolean acquire = connection.setNX(lockKey.getBytes(), String.valueOf(nowTime + lockExpireMils + 1).getBytes());
            if (acquire) {
                return Boolean.TRUE;
            } else {
                byte[] value = connection.get(lockKey.getBytes());
                if (Objects.nonNull(value) && value.length > 0) {
                    long oldTime = Long.parseLong(new String(value));
                    if (oldTime < nowTime) {
                        //connection.getSet:返回这个key的旧值并设置新值。
                        byte[] oldValue = connection.getSet(lockKey.getBytes(), String.valueOf(nowTime + lockExpireMils + 1).getBytes());
                        //当key不存时会返回空,表示key不存在或者已在管道中使用
                        return oldValue == null ? false : Long.parseLong(new String(oldValue)) < nowTime;
                    }
                }
            }
            return Boolean.FALSE;
        });
    }

参考地址

RedisTemplate用SETNX命令实现分布式锁 https://www.jianshu.com/p/6dd656e7051f

原文地址:https://www.cnblogs.com/kiko2014551511/p/11801138.html

时间: 2024-12-25 12:43:46

redisTemplate通过setNx实现分布式锁的相关文章

redis分布式锁-SETNX实现

转自:https://my.oschina.net/u/1995545/blog/366381 Redis有一系列的命令,特点是以NX结尾,NX是Not eXists的缩写,如SETNX命令就应该理解为:SET if Not eXists.这系列的命令非常有用,这里讲使用SETNX来实现分布式锁. 用SETNX实现分布式锁 利用SETNX非常简单地实现分布式锁.例如:某客户端要获得一个名字foo的锁,客户端使用下面的命令进行获取: SETNX lock.foo <current Unix tim

使用Redis SETNX 命令实现分布式锁

转自:http://blog.csdn.net/lihao21/article/details/49104695 使用Redis的 SETNX 命令可以实现分布式锁,下文介绍其实现方法. SETNX命令简介 命令格式 SETNX key value 将 key 的值设为 value,当且仅当 key 不存在. 若给定的 key 已经存在,则 SETNX 不做任何动作. SETNX 是SET if Not eXists的简写. 返回值 返回整数,具体为 - 1,当 key 的值被设置 - 0,当

不为人所知的分布式锁实现全都在这里了!

1.引入业务场景 首先来由一个场景引入: 最近老板接了一个大单子,允许在某终端设备安装我们的APP,终端设备厂商日活起码得几十万到百万级别,这个APP也是近期产品根据市场竞品分析设计出来的,几个小码农通宵达旦开发出来的,主要功能是在线购物一站式服务,后台可以给各个商家分配权限,来维护需要售卖的商品信息. 老板大O:谈下来不容易,接下来就是考虑如何吸引终端设备上更多的用户注册上来,如何引导用户购买,这块就交给小P去负责了,需求尽快做,我明天出差! 产品小P:嘿嘿~,眼珠一转儿,很容易就想到了,心里

整理分布式锁:业务场景&amp;分布式锁家族&amp;实现原理

1.引入业务场景 业务场景一出现: 因为小T刚接手项目,正在吭哧吭哧对熟悉着代码.部署架构.在看代码过程中发现,下单这块代码可能会出现问题,这可是分布式部署的,如果多个用户同时购买同一个商品,就可能导致商品出现 库存超卖 (数据不一致) 现象,对于这种情况代码中并没有做任何控制. 原来一问才知道,以前他们都是售卖的虚拟商品,没啥库存一说,所以当时没有考虑那么多... 这次不一样啊,这次是售卖的实体商品,那就有库存这么一说了,起码要保证不能超过库存设定的数量吧. 小T大眼对着屏幕,屏住呼吸,还好提

[转载] Redis实现分布式锁

转载自http://zhidao.baidu.com/link?url=m56mmWYwRgCymsaLZ2tx-GWDy5FYmUWGovEtuApjTpktHS3bhofrCS-QVGiLoWeS0P-9xeS3p1n8eDqZv-D9KlHXGFYT-1BjC1xmKTnHNkG和http://blog.csdn.net/java2000_wl/article/details/8740911 Redis有一系列的命令,特点是以NX结尾,NX是Not eXists的缩写,如SETNX命令就应

关于redis实现分布式锁

前言 分布式锁一般有三种实现方式:1. 数据库乐观锁:2. 基于Redis的分布式锁:3. 基于ZooKeeper的分布式锁.本篇博客将介绍第二种方式,基于Redis实现分布式锁.虽然网上已经有各种介绍Redis分布式锁实现的博客,然而他们的实现却有着各种各样的问题,为了避免误人子弟,本篇博客将详细介绍如何正确地实现Redis分布式锁. 可靠性 首先,为了确保分布式锁可用,我们至少要确保锁的实现同时满足以下四个条件: 互斥性.在任意时刻,只有一个客户端能持有锁. 不会发生死锁.即使有一个客户端在

基于redis的分布式锁实现

关于分布式锁 很久之前有讲过并发编程中的锁并发编程的锁机制:synchronized和lock.在单进程的系统中,当存在多个线程可以同时改变某个变量时,就需要对变量或代码块做同步,使其在修改这种变量时能够线性执行消除并发修改变量.而同步的本质是通过锁来实现的.为了实现多个线程在一个时刻同一个代码块只能有一个线程可执行,那么需要在某个地方做个标记,这个标记必须每个线程都能看到,当标记不存在时可以设置该标记,其余后续线程发现已经有标记了则等待拥有标记的线程结束同步代码块取消标记后再去尝试设置标记.

分布式锁详解

基于数据库: 基于数据库表做乐观锁,用于分布式锁.(version) 基于数据库表做悲观锁(InnoDB,for update) 基于数据库表数据记录做唯一约束(表中记录方法名称) 基于缓存: 使用redis的setnx()用于分布式锁.(setNx,直接设置值为当前时间+超时时间,保持操作原子性) 使用memcached的add()方法,用于分布式锁. 使用Tair的put()方法,用于分布式锁. 基于Zookeeper: 每个客户端对某个方法加锁时,在zookeeper上的与该方法对应的指定

扩展redisTemplate实现分布式锁

原文:https://blog.csdn.net/qq1010267837/article/details/79697572 依赖jar包 compile group: 'redis.clients', name: 'jedis', version:'2.8.1'compile group: 'org.springframework.data', name: 'spring-data-redis', version:'1.6.5.RELEASE' /** * Redis的分布式锁对象 * Cre