【redis】——分布式锁

Redis实战之 分布式锁 重入问题:重入问题是指 获得锁的线程可以再次进入到相同的锁的代码块中,可重入锁的意义在于防止死锁,比如HashTable这样的代码中,他的方法都是使用synchronized修饰的,假如他在一个方法内,调用另一个方法,那么此时如果是不可重入的,不就死锁了吗?所以可重入锁他的主要意义是防止死锁,我们的synchronized和Lock锁都是可重入的。不可重试:是指目前的分布式只能尝试一次,我们认为合理的情况是:当线程在获得锁失败后,他应该能再次尝试获得锁。 阅读详情


原创hy_coming 最后发布于2019-07-07 16:56:10 阅读数 33  已收藏
展开
实例代码地址,请前往:https://gitee.com/GuoqingLee/distributed-seckill

redis官方文档地址,请前往:http://www.redis.cn/topics/distlock.html

前言
关于分布式锁的实现,目前主流方案有以下三类:

1、基于数据库的乐观锁;

2、基于redis实现的锁服务;

3、基于zookeeper的实现;

本文注释基于redis实现分布式锁,一种是最普通的实现方式,另外一种是redis官网推荐的实现方式redission实现,接下看看实现代码

一、普通实现方式
普通实现方式是基于以下两个命令

#使用redis中的setnx命令创建一个key,成功创建就是加锁
SET resource_name my_random_value NX PX 30000
 
#删除锁的时候,找到 key 对应的 value,跟自己传过去的 value 做比较,如果是一样的才删除。
if redis.call("get",KEYS[1]) == ARGV[1] then
    return redis.call("del",KEYS[1])
else
    return 0
end
依赖引入

        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
        </dependency>
代码实现

/**
 * @author  2019/7/7 15:49
 */
public class RedisLocker {
    @Autowired
    private JedisPool jedisPool;
 
    /**
     * 获取锁
     *
     * @param key
     * @param value
     * @param leaseTime 过期时间
     * @return
     */
    public boolean tryLock(String key, String value, long leaseTime) {
        try (Jedis jedis = jedisPool.getResource()) {
            if (jedis == null) {
                return false;
            }
            String result = jedis.set(key, value, "NX", "PX", leaseTime);
            return "OK".equalsIgnoreCase(result);
        } catch (Exception e) {
            return false;
        }
    }
 
    /**
     * 释放锁 
     * @param key
     * @param value
     * @return
     */
    public int unlock(String key, String value) {
        try (Jedis jedis = jedisPool.getResource()) {
            if (jedis == null) {
                return 0;
            }
            StringBuilder builder = new StringBuilder();
            builder.append("if redis.call('get','")
                    .append(key)
                    .append("')")
                    .append("=='")
                    .append(" then ")
                    .append("  return redis.call('del','")
                    .append(key)
                    .append("')")
                    .append(" else ")
                    .append(" return 0")
                    .append(" end");
            return Integer.valueOf(jedis.eval(builder.toString()).toString());
        }catch (Exception e){
            return 0;
        }
    }
 
 
}
结果请自行测试

二、基于redission实现
依赖引入

        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson-spring-boot-starter</artifactId>
            <version>3.10.1</version>
        </dependency>
配置文件

#redis config
spring.redis.database=
spring.redis.host=
spring.redis.port=
spring.redis.password=
spring.redis.ssl=
spring.redis.timeout=
spring.redis.cluster.nodes=
spring.redis.sentinel.master=
spring.redis.sentinel.nodes=
代码实现

/**
 * 基于redission的分布式实现
 *
 * @author  2019/7/7 15:20
 */
@Component
public class RedissonDistributedLocker {
    @Autowired
    private RedissonClient redissonClient;
 
    /**
     * 加锁
     *
     * @param lockKey
     * @return
     */
    public RLock lock(String lockKey) {
        RLock lock = redissonClient.getLock(lockKey);
        lock.lock();
        return lock;
    }
 
 
    /**
     * 加锁,过期自动释放
     *
     * @param lockKey
     * @param leaseTime
     * @return
     */
    public RLock lock(String lockKey, long leaseTime) {
        RLock lock = redissonClient.getLock(lockKey);
        lock.lock(leaseTime, TimeUnit.SECONDS);
        return lock;
    }
 
    /**
     * 加锁,过期自动释放,传入时间单位
     *
     * @param lockKey
     * @param leaseTime
     * @param unit
     * @return
     */
    public RLock lock(String lockKey, long leaseTime, TimeUnit unit) {
        RLock lock = redissonClient.getLock(lockKey);
        lock.lock(leaseTime, unit);
        return lock;
    }
 
    /**
     * 尝试获取锁,传入时间单位
     *
     * @param lockKey
     * @param unit
     * @param waitTime
     * @param leaseTime
     * @return
     */
    public boolean tryLock(String lockKey, TimeUnit unit, long waitTime, long leaseTime) {
        RLock lock = redissonClient.getLock(lockKey);
        try {
            return lock.tryLock(waitTime, leaseTime, unit);
        } catch (InterruptedException e) {
            return false;
        }
    }
 
    /**
     * 尝试获取锁
     *
     * @param lockKey
     * @param waitTime
     * @param leaseTime
     * @return
     */
    public boolean tryLock(String lockKey, long waitTime, long leaseTime) {
        RLock lock = redissonClient.getLock(lockKey);
        try {
            return lock.tryLock(waitTime, leaseTime, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            return false;
        }
    }
 
    /**
     * 释放锁,传入key
     *
     * @param lockKey
     */
    public void unlock(String lockKey) {
        redissonClient.getLock(lockKey).unlock();
    }
 
    /**
     * 释放锁,传入lock
     *
     * @param lock
     */
    public void unlock(RLock lock) {
        lock.unlock();
    }
}
结果测试

#方式一
@Autowired
 private RedissonDistributedLocker redissonDistributedLocker;
 
String lockKey = "BM_MARKET_SECKILL_" + stallActivityId;
try {
                //超过2S自动释放锁
        redissonDistributedLocker.lock(lockKey, 2L);
                //业务处理
 
    } finally {
        redissonDistributedLocker.unlock(lockKey);  //释放锁
    }
 
#方式二
@Autowired
private RedissonDistributedLocker redissonDistributedLocker;
 
public void test() throws InterruptedException {
    final int[] counter = {0};
 
        for (int i= 0; i < 100; i++){
        
            new Thread(new Runnable() {
 
                @Override
 
                public void run() {
                    boolean isGetLock = redissonDistributedLocker.tryLock("test0001", 3L, 1L);
                    if(isGetLock) {
                        try {
                            int a = counter[0];
                            counter[0] = a + 1;
                            logger.info(a + "");
                        } finally {
                            redissonDistributedLocker.unlock("test0001");
                        }
                    }
                }
            }).start();
            
        }
 
        // 主线程休眠,等待结果
        Thread.sleep(5000);
        System.out.println(counter[0]);
        logger.info(counter[0] + "");
}
三、redis 分布式锁和 zk 分布式锁的对比
redis 分布式锁,其实需要自己不断去尝试获取锁,比较消耗性能。
zk 分布式锁,获取不到锁,注册个监听器即可,不需要不断主动尝试获取锁,性能开销较小。
另外一点就是,如果是 redis 获取锁的那个客户端 出现 bug 挂了,那么只能等待超时时间之后才能释放锁;而 zk 的话,因为创建的是临时 znode,只要客户端挂了,znode 就没了,此时就自动释放锁。

redis 分布式锁大家没发现好麻烦吗?遍历上锁,计算时间等等......zk 的分布式锁语义清晰实现简单。

参考:https://www.cnblogs.com/ocean-sky/p/10320627.html

http://www.redis.cn/topics/distlock.html

 

distributed-locker:注解方式实现分布式锁 distributed-locker 注解方式实现分布式锁 将jar包引入 在需要添加分布式锁的方法上加上@CacheLock(prefix="xxx") , prefix为key的前缀 需要组成key的参数使用 @CacheParam 如 @CacheParam("token") 完成 立即下载

相关推荐

绝对旋转编码器学习笔记(基本原理,与PC通信等,不定期更新中)

前言 最近开始学习编码器相关内容,目的在于搞清楚编码器的原理,与上位机的联系等问题。笔记资料来源为网络,整理的同时也会有一些总结和感悟。由于研究方向需求,主要研究数字旋转编码器。 1.编码器的定义 编码器(encoder)是将信号(如比特流)或数据进行编制、转换为可用以通讯、传输和存储的信号形式的设备。——摘自《百度百科》 通常来说,编码器可以将角度位移、直线位移、转速等物理量转换为电信号。这里的电信号根据不同原理的编码器输出脉冲、二进制数码等不同的类型,下面会提到。 2.编码器的分类 编.

黑化咸鱼的博客 1万+

分布式锁介绍及实现

一、什么是分布式锁? 要介绍分布式锁,首先要提到与分布式锁相对应的是线程锁、进程锁。 线程锁:主要用来给方法、代码块加锁。当某个方法或代码使用锁,在同一时刻仅有一个线程执行该方法或该代码段。线程锁只在同一JVM中有效果,因为线程锁的实现在根本上是依靠线程之间共享内存实现的,比如synchronized是共享对象头,显示锁Lock是共享某个变量(state)。 分布式锁:当多个进程不在同一个系...

haoxin963的专栏 1261

手把手教你搞定CAC会议投稿:从LaTeX模板到PDF eXpress避坑全流程

本文详细解析CAC会议投稿全流程,重点介绍LaTeX模板调整、Turnitin查重技巧及PDF eXpress校验避坑指南。通过实战案例和代码示例,帮助研究者高效完成IEEE格式论文投稿,避免常见技术性失误,提升投稿成功率。

weixin_29969209的博客 397

一文讲清楚分布式事务+分布式锁实现及各技能知识要点

分布式锁Redisson讲解,分布式锁控制超卖,Seata分布式事务讲解,普通商品抢单分布式事务,WebSocket讲解。本文实际解决了大并发场景下技术实现过程。

怀揣梦想,一颗执着于技术的心从未磨灭,内心住着一颗顽强的小强时刻提醒自己层层突破自我,同时也成就他人 1521

主流双目相机技术参数横向评测:从ZED到国产新锐

本文对主流双目相机技术参数进行了横向评测,涵盖ZED、Bumblebee等国际品牌及国产新锐产品。详细分析了分辨率、帧率、视场角等关键参数,并针对机器人导航、AR/VR交互、工业检测等场景提供选型建议。特别推荐ZED相机在科研领域的成熟应用,以及国产方案在长基线设计和主动双目技术上的创新突破。

weixin_33670786的博客 317

无人机核心部件解析:从机架到飞控的全面指南

本文全面解析无人机的核心部件,从机架材质选择到飞控系统调参,提供专业指南。重点介绍碳纤维机架、无刷电机搭配、锂聚合物电池管理及飞控传感器配置,帮助读者掌握无人机组装与优化的关键技术,适用于航拍、测绘、农业植保等多种应用场景。

weixin_30872499的博客 465

分布式锁(Distributed Lock)介绍(基于数据库(mysql);基于缓存(redis);基于ZooKeeper等分布式协调服务)

分布式锁是一种在分布式环境下,对共享资源提供访问限制的方法。其主要目的是防止多个进程同时操作同一资源,造成数据的不一致性。分布式锁通过在多个节点上运行的进程之间引入协调机制,来解决这个问题。分布式锁是一种有效的协调在分布式环境中运行的并发进程的机制。它可以帮助我们避免因并发操作而导致的数据不一致性。然而,设计和实现一个可靠、高效且公平的分布式锁是一项具有挑战性的任务。

Dontla的博客 4394

海思Hi3061M MCU:为高速吹风筒市场注入智能动力

此外,海思还提供了丰富的软件开发工具和生态环境组件,帮助开发者快速实现复杂功能。高速吹风筒因其高效的风力和快速的干燥效果,近年来在市场上越来越受欢迎。然而,传统的高速吹风筒在性能、噪音和使用寿命等方面仍有改进的空间。凭借其高性能、低功耗、低噪声和易用的开发工具,为高速吹风筒市场带来了全新的解决方案。这不仅提高了用户的使用体验,还延长了电机的使用寿命。这不仅减少了电机的电磁噪声,还提高了电机的运行效率。还支持风机顺逆风启动适配多种电阻范围的电机,进一步提高了吹风筒的适用性和灵活性。

2401_83448585的博客 2015

Redisson分布式锁实现

一、锁的实现原理 在一些场景中,我们希望一个方法同一时间只被一个线程执行,如果在单机环境下我们可以通过使用Java提供的并发API来限制访问,同一个JVM的线程可以通过共享堆内存中的变量来标记,这个标记其实就是锁,synchronized是通过对象头来标记;Lock接口的实现类是通过一个volatile的int型变量state来实现多线程的可见性和有序性(防止指令被重排序);linux 内核中也...

猫小妖的专栏 1104

Shopee动态参数x-sap-Ri与x-sap-Sec逆向解析实战

现代电商前端反爬普遍采用动态参数校验机制,其核心是将设备指纹、DOM状态与时间上下文耦合生成不可复用的请求凭证。x-sap-Ri本质是渲染上下文唯一标识,依赖真实浏览器环境中的DOM树结构、Canvas像素指纹及毫秒级时间扰动;x-sap-Sec则是基于该标识与服务端同步密钥生成的HMAC-SHA256签名,具备强时效性与密钥轮换特性。这类机制显著提升了自动化采集门槛,广泛应用于Shopee商品详情页等高价值数据接口。本文聚焦于从Chrome DevTools调试出发,系统还原参数生成逻辑,覆盖DOM一致性

weixin_30603633的博客 893

YOLO11涨点优化:知识蒸馏 | 引入FGD(Focal and Global Distillation)蒸馏,让轻量学生模型汲取大模型全局感知力

文章摘要 目标检测模型YOLO11在轻量化部署中存在"全局盲区"问题,即轻量模型感受野不足导致大尺度场景下性能下降。知识蒸馏技术FGD(Focal and Global Distillation)通过双分支机制有效解决这一问题:Focal Distillation分离前景背景特征,让学生模型聚焦关键区域;Global Distillation传递像素间关系信息,弥补全局感知缺陷。实验表明,FGD可使YOLO11轻量版mAP提升2.5%以上,且不增加推理耗时。本文详细解析了FGD原理,并给出YOLO11上的实

2601_95807009的博客 226

RedissonDistributedLocker+自定义注解实现接口防止重复提交

*** @description: 幂等注解*//*** 参数的表达式,用来确定key值,例如:"#req.saleInfo.channelCode,#req.seqId"* @return*//*** 幂等过期时间,即:在此时间段内,对API进行幂等处理。*//*** 参数的表达式,用来确定key值* @return*//*** 幂等过期时间,即:在此时间段内,对API进行幂等处理*/

weixin_43195437的博客 1360

Zemax与Matlab交互:双胶合优化详细流程

Zemax与Matlab交互:双胶合优化详细流程

weixin_72050316的博客 629

Redis实现分布式锁

在多线程并发的情况下,我们可以使用锁来保证一个代码块在同一时间内只能由一个线程访问。比如Java的synchronized关键字和Reentrantlock类等等。 这样子可以保证在同一个JVM进程内的多个线程同步执行。 如果在分布式的集群环境中,如何保证不同节点的线程同步执行呢? 怎么才能在分布式系统中,实现不同线程对代码和资源的同步访问? 对于单进程的并发场景,我们可以使用语言...

forever-and-ever的博客 4万+

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

Redis的分布式锁分析

开发同学都知道,在分布式系统中,为了保证多个机器并发操作的数据一致性,常常需要使用分布式锁机制。常用的比如数据库锁,ZK锁,Reis锁等等,今天我们就探讨下Redis分布式锁,说说他的实现原理和应用场景,并介绍如何正确使用分布式锁来解决并发问题

战斧的博客 7259

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

Redis的分布式锁

Redis分布式锁通过Redis原子操作实现互斥访问,核心是SETNX命令设置带过期时间的键值对,配合Lua脚本确保安全释放。Java实现可通过Jedis手动处理锁获取、唯一标识验证和释放逻辑,或使用Redisson简化开发,其提供自动续期、可重入锁等功能。Redlock算法支持多节点部署提高可靠性。注意事项包括合理设置锁超时、确保原子操作、处理时钟漂移等。适用于秒杀、任务调度等需要互斥访问的场景,Jedis适合简单需求,Redisson更适合复杂场景,能显著降低开发复杂度。

Hzx895554135的博客 2691

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

Redis分布式锁实现

如果负责储存这个分布式锁的Redisson节点宕机以后,而且这个锁正好处于锁住的状态时,这个锁会出现锁死的状态。为了避免这种情况的发生,Redisson内部提供了一个监控锁的看门狗,它的作用是在Redisson实例被关闭前,不断的延长锁的有效期。默认情况下,看门狗的检查锁的超时时间是30秒钟,也可以通过修改Config.lockWatchdogTimeout来另行指定。另外Redisson还通过加锁的方法提供了leaseTime的参数来指定加锁的时间。超过这个时间后锁便自动解开了。

учёба 2401

Redis 实现分布式锁

本文主要介绍了Redis的分布式锁。涉及Reids的原子操作,分布式锁,Redis的事务,以及用Go语言实现通过Lua脚本来扣减库存。

tatasix的博客 1818

redis 分布式锁实现

分布式锁

weixin_44550507的博客 2040

分布式锁【Redis场景分布式锁篇】

分布式锁,Redis锁,Redis

席万里的博客 2411

[Redis] 基于redis的分布式锁

前言 分布式锁一般有三种实现方式:1. 数据库乐观锁;2. 基于Redis的分布式锁;3. 基于ZooKeeper的分布式锁。本篇博客将介绍第二种方式,基于Redis实现分布式锁。 可靠性 首先,为了确保分布式锁可用,我们至少要确保锁的实现同时满足以下四个条件: 互斥性。在任意时刻,只有一个客户端能持有锁。 不会发生死锁。即使有一个客户端在持有锁的期间崩溃而没有主动解锁,也能保证后续其他...

1.02^365的成长裂变 3万+

redis分布式锁

redis分步式锁

m0_73866527的博客 1642

Redis分布式锁

且redisson提供了锁的重试机制,也就是持锁期间有其他线程来请求,那么其他的线程获取锁失败后就会一直循环获取,当然会有一个循环的阈值,这样的好处就是在高并发情况下,能够很好的提高分布式锁的使用性能。redisson实现的分布式锁是可重入的,它的底层使用的是hash数据结构,记录的是线程的id和重入的次数。首先,当一个线程获取分布式锁成功后,锁的默认持有时间为30秒,看门狗机制会每隔锁的持有时间%3,也就是10s来检测当前业务是否还持有锁,若持有锁则继续增加锁的持有时间,完成业务后会自动释放锁。

m0_74808313的博客 1550

Redis分布式锁详解

分布式锁是在分布式系统中用于控制多个进程/服务对共享资源进行互斥访问的一种机制。在单机系统中,我们可以使用语言提供的锁机制(如Java的synchronized或ReentrantLock),但在分布式环境下,这些本地锁无法跨进程/机器工作,因此需要分布式锁。

JAVA领域优质创作者,基于分片网络查询方法专利发明者。 1672
上一篇: 事务的四大特性(一)
下一篇: 分布式架构下基于Redisson实现Redis分布式锁
王树民
博客等级 码龄10年 912粉丝 560原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值