分布式锁的作用及实现(Redis)

分布式锁:场景和使用方法(通俗讲解) 对于锁大家肯定不会陌生,比如 synchronized 关键字 和 ReentrantLock 可重入锁,一般我们用其在多线程环境中控制对资源的并发访问。但是随着业务的发展,分布式的概念逐渐出现在我们系统中,我们在开发的过程中经常需要进行多个系统之间的交互,于是上面的加锁方法就会失去作用。于是在分布式锁就自然而然的诞生了,接下来我们来聊一聊分布式锁实现的几种方式。 阅读详情

一、什么是分布式锁?

要介绍分布式锁,首先要提到与分布式锁相对应的是线程锁、进程锁。

线程锁:主要用来给方法、代码块加锁。当某个方法或代码使用锁,在同一时刻仅有一个线程执行该方法或该代码段。线程锁只在同一JVM中有效果,因为线程锁的实现在根本上是依靠线程之间共享内存实现的,比如synchronized是共享对象头,显示锁Lock是共享某个变量(state)。

进程锁:为了控制同一操作系统中多个进程访问某个共享资源,因为进程具有独立性,各个进程无法访问其他进程的资源,因此无法通过synchronized等线程锁实现进程锁。

分布式锁:当多个进程不在同一个系统中,用分布式锁控制多个进程对资源的访问。

二、分布式锁的使用场景。

线程间并发问题和进程间并发问题都是可以通过分布式锁解决的,但是强烈不建议这样做!因为采用分布式锁解决这些小问题是非常消耗资源的!分布式锁应该用来解决分布式情况下的多进程并发问题才是最合适的。

有这样一个情境,线程A和线程B都共享某个变量X。

如果是单机情况下(单JVM),线程之间共享内存,只要使用线程锁就可以解决并发问题。

如果是分布式情况下(多JVM),线程A和线程B很可能不是在同一JVM中,这样线程锁就无法起到作用了,这时候就要用到分布式锁来解决。

三、分布式锁的实现(Redis)

分布式锁实现的关键是在分布式的应用服务器外,搭建一个存储服务器,存储锁信息,这时候我们很容易就想到了Redis。首先我们要搭建一个Redis服务器,用Redis服务器来存储锁信息。

在实现的时候要注意的几个关键点:

1、锁信息必须是会过期超时的,不能让一个线程长期占有一个锁而导致死锁;

2、同一时刻只能有一个线程获取到锁。

几个要用到的redis命令:

setnx(key, value):“set if not exits”,若该key-value不存在,则成功加入缓存并且返回1,否则返回0。

get(key):获得key对应的value值,若不存在则返回nil。

getset(key, value):先获取key对应的value值,若不存在则返回nil,然后将旧的value更新为新的value。

expire(key, seconds):设置key-value的有效期为seconds秒。

看一下流程图:


在这个流程下,不会导致死锁。

我采用Jedis作为Redis客户端的api,下面来看一下具体实现的代码。

(1)首先要创建一个Redis连接池。

public class RedisPool {

    private static JedisPool pool;//jedis连接池

    private static int maxTotal = 20;//最大连接数

    private static int maxIdle = 10;//最大空闲连接数

    private static int minIdle = 5;//最小空闲连接数

    private static boolean testOnBorrow = true;//在取连接时测试连接的可用性

    private static boolean testOnReturn = false;//再还连接时不测试连接的可用性

    static {
        initPool();//初始化连接池
    }

    public static Jedis getJedis(){
        return pool.getResource();
    }

    public static void close(Jedis jedis){
        jedis.close();
    }

    private static void initPool(){
        JedisPoolConfig config = new JedisPoolConfig();
        config.setMaxTotal(maxTotal);
        config.setMaxIdle(maxIdle);
        config.setMinIdle(minIdle);
        config.setTestOnBorrow(testOnBorrow);
        config.setTestOnReturn(testOnReturn);
        config.setBlockWhenExhausted(true);
        pool = new JedisPool(config, "127.0.0.1", 6379, 5000, "liqiyao");
    }
}

(2)对Jedis的api进行封装,封装一些实现分布式锁需要用到的操作。

public class RedisPoolUtil {

    private RedisPoolUtil(){}

    private static RedisPool redisPool;

    public static String get(String key){
        Jedis jedis = null;
        String result = null;
        try {
            jedis = RedisPool.getJedis();
            result = jedis.get(key);
        } catch (Exception e){
            e.printStackTrace();
        } finally {
            if (jedis != null) {
                jedis.close();
            }
            return result;
        }
    }

    public static Long setnx(String key, String value){
        Jedis jedis = null;
        Long result = null;
        try {
            jedis = RedisPool.getJedis();
            result = jedis.setnx(key, value);
        } catch (Exception e){
            e.printStackTrace();
        } finally {
            if (jedis != null) {
                jedis.close();
            }
            return result;
        }
    }

    public static String getSet(String key, String value){
        Jedis jedis = null;
        String result = null;
        try {
            jedis = RedisPool.getJedis();
            result = jedis.getSet(key, value);
        } catch (Exception e){
            e.printStackTrace();
        } finally {
            if (jedis != null) {
                jedis.close();
            }
            return result;
        }
    }

    public static Long expire(String key, int seconds){
        Jedis jedis = null;
        Long result = null;
        try {
            jedis = RedisPool.getJedis();
            result = jedis.expire(key, seconds);
        } catch (Exception e){
            e.printStackTrace();
        } finally {
            if (jedis != null) {
                jedis.close();
            }
            return result;
        }
    }

    public static Long del(String key){
        Jedis jedis = null;
        Long result = null;
        try {
            jedis = RedisPool.getJedis();
            result = jedis.del(key);
        } catch (Exception e){
            e.printStackTrace();
        } finally {
            if (jedis != null) {
                jedis.close();
            }
            return result;
        }
    }
}

(3)分布式锁工具类

public class DistributedLockUtil {

    private DistributedLockUtil(){
    }

    public static boolean lock(String lockName){//lockName可以为共享变量名,也可以为方法名,主要是用于模拟锁信息
        System.out.println(Thread.currentThread() + "开始尝试加锁!");
        Long result = RedisPoolUtil.setnx(lockName, String.valueOf(System.currentTimeMillis() + 5000));
        if (result != null && result.intValue() == 1){
            System.out.println(Thread.currentThread() + "加锁成功!");
            RedisPoolUtil.expire(lockName, 5);
            System.out.println(Thread.currentThread() + "执行业务逻辑!");
            RedisPoolUtil.del(lockName);
            return true;
        } else {
            String lockValueA = RedisPoolUtil.get(lockName);
            if (lockValueA != null && Long.parseLong(lockValueA) >= System.currentTimeMillis()){
                String lockValueB = RedisPoolUtil.getSet(lockName, String.valueOf(System.currentTimeMillis() + 5000));
                if (lockValueB == null || lockValueB.equals(lockValueA)){
                    System.out.println(Thread.currentThread() + "加锁成功!");
                    RedisPoolUtil.expire(lockName, 5);
                    System.out.println(Thread.currentThread() + "执行业务逻辑!");
                    RedisPoolUtil.del(lockName);
                    return true;
                } else {
                    return false;
                }
            } else {
                return false;
            }
        }
    }
}

深入理解Redis分布式锁 背景 项目中有个场景是做数据分析,然后将目标数据保存在db,有个要求是将同类型的目标数据值保存一次,因此每次保存时需要判断之前是否已经存在了,由于qps较高,之前使用redis来缓存已经保存的数据,来抵挡对db的大部分流量,最近业务拓展同类型目标数据的qps可能超大(极限时达到20Wqps以上),此时由于在分布式场景下redis查询未加锁,可能多个线程同时查询redis得到的结果为并未保存,此时问题发生了,可能同时有多个线程执行保存到db操作,虽然db做了unique Key的限制,但担心到db qps过高 阅读详情

相关推荐

Redis实现分布式锁的核心原理以及利弊

文章目录INFO一、关键点1、原子性2、过期时间3、锁续期4、释放锁二、Redis实现分布式锁的几种方式1、单机2、哨兵3、集群4、红锁三、Redis实现分布式锁的利弊1、优点2、缺点四、总结 INFO 作者: 编程界的小学生 日期: 2021/09/06 修订: 初版,未修订。2021/09/06 版权: 内部资料,切勿泄漏,违者必究。 一、关键点 原子性 过期时间 释放锁 锁续期 1、原子性 比如如下就不具有原子性,就是错误的代码: boolean lockStatus = stringRedisT

【原】编程界的小学生 1717

看完这篇分布式锁,再也不迷惑了

分布式锁介绍

weixin_46906359的博客 1372

面积二次矩second moment of area 极惯性矩polar moment of area 转动惯量moment of inertia面积一次矩first moment of area

看论文记录一下力学的名词专业术语,后面可以查看。

subtitle_的博客 5367

什么是分布式锁,分布式锁有什么作用?

为了防止分布式系统中的多个进程之间相互干扰,我们需要一种分布式协调技术来对这些进程进行调度。而这个分布式协调技术的核心就是来实现这个分布式锁。

记得微笑的博客 5926

用Coze平台30分钟打造《花光10亿》小游戏:零代码AI开发实战

本文详细介绍了如何利用字节跳动推出的Coze平台,在30分钟内零代码开发一款名为《花光10亿》的AI小游戏。通过配置提示词、集成图像生成插件、构建自动化工作流以及使用数据库功能,即使没有编程基础的用户也能快速将创意转化为可交互的智能应用,体验AI开发的便捷与高效。

weixin_29313547的博客 206

Hadoop实战:用MapReduce分析YouTube视频数据集(附完整代码)

本文提供了一个完整的Hadoop MapReduce实战教程,指导读者使用MapReduce框架分析YouTube视频数据集,统计不同视频类别的数量分布。教程涵盖从数据获取、预处理、HDFS操作到Java代码编写、作业提交及结果可视化的全流程,并附有完整代码,帮助开发者深入理解分布式计算思想。

lilh34434的博客 197

Redis 分布式锁深度解析:setnx 命令的核心作用与实现

Redis 分布式锁的核心是通过SET NX PX命令实现原子性的 "抢锁",并通过 Lua 脚本保证释放锁的安全性。SETNX(或SET NX)是实现锁的基础,解决了并发抢锁的原子性问题必须给锁设置过期时间,避免死锁释放锁时需通过唯一标识 + Lua 脚本,防止误删其他客户端的锁实际应用中需考虑超时、可重入性、集群一致性等进阶问题掌握这些原理后,再去阅读 Redisson 等框架的源码,就能更清晰地理解其设计思路。

java_beautiful的博客 1104

【硬件开发】振铃

如果是开关管的振铃,那么桥臂的SW处产生的振铃会窜入驱动电路,造成的结果就是驱动电路和上桥臂下桥臂之间的SW节点都会有振铃现象。如果是驱动电路的振铃,那么MCU的输出引脚还是正常的PWM,但是到了MOS管两侧就变成带有振铃的PWM波形了。开关振铃产生的原因是MOS管上面的寄生电感当开关管打开时为了保持电流不变感应出的电压会对电源和地产生冲击。开关管的驱动线上的寄生电容和寄生电感导致的振铃为驱动电路振铃。开关管上的寄生电容和寄生电感导致的振铃为开关节点振铃。、电感等元件的存在,导致电路中的电压和。

weixin_62546664的博客 1821

Redis中的SETNX命令有什么作用?如何使用它来实现分布式锁?

但是,为了确保安全地释放锁,通常会检查锁是否是由当前客户端设置的,只有当确认无误时才删除键。请注意,即使使用了这些技术,分布式锁仍然可能遇到一些边缘情况,比如时钟漂移、网络延迟等,所以在实际应用中可能还需要考虑更多的细节来确保系统的可靠性。分布式锁的作用是在多个客户端之间同步对共享资源的访问,确保同一时间只有一个客户端可以修改该资源。如果持有锁的客户端崩溃或忘记释放锁,那么其他客户端可以在锁超时后重新获取锁。尝试设置一个唯一的锁标识(例如,一个随机生成的 UUID 或者客户端 ID)。

qq_33240556的博客 1368

RK806S PMIC电源管理芯片调试

当点按PWRON按键时,rk806上电开始启动bootloader和uboot,在执行到此处时检测到是由于按键启动的,所以0x5d的值是0x80,0x74的值是0x80,在一般情况下,mode都默认是none的,所以mode值为11,因此就进入了我们的if判断,若是由于按键启动的,则直接调用rk8xx_shutdown函数关掉,进入这个函数会看到实际是通过i2c给0x72寄存器的BIT(0)写1,使其关机。当SoC在12V电源已经接入,且处于关机状态时,使用PWRON按键开机,0x74的值则为0x80。

Y1anoohh的博客 2539

通讯模块_三菱IQ-R PLC串口通讯模块RJ71C24进行Modbus-RTU通讯

在日常的选型中,很多电气工程师咨询我,三菱iQ-R系列有没有Modbus通讯模块,我在这里可以肯定的回复您,这个肯定是有的;我们共有三种可以选择分别是RJ71C24、RJ71C24-R2、RJ71C24-R4。RJ71C24系列支持MC协议通信、通信协议通信、无顺序协议通信、双向协议通信全、MODBUS通信。当我帮助他们选型之后,他们在使用的时候,又是一头雾水。那么今天我抽一些时间讲解一RJ71...

weixin_39878549的博客 9266

redis分布式锁的作用及实现

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

ntotl的博客 6292

如何在 R 中执行 Kruskal-Wallis 检验

Kruskal-Wallis 检验用于确定三个或更多独立组的中位数之间是否存在统计学上的显着差异。它被认为是单向方差分析的非参数等效项。本教程介绍了如何在 R 中执行 Kruskal-Wallis 检验。示例:R 中的 Kruskal-Wallis 检验 假设研究人员想知道三种不同的肥料是否会导致不同水平的植物生长。他们随机选择 30 种不同的植物并将它们分成三组,每组 10 株,每组施用不同的肥料。在一个月结束时,他们测量每株植物的高度。使用以下步骤执行 Kruskal-Wallis 检验以确定三个组的中

Mrrunsen的博客 3796

分布式锁的作用及实现(Redis,RedisReentrantLock)

https://blog.youkuaiyun.com/l_bestcoder/article/details/79336986一、什么是分布式锁?要介绍分布式锁,首先要提到与分布式锁相对应的是线程锁、进程锁。线程锁:主要用来给方法、代码块加锁。当某个方法或代码使用锁,在同一时刻仅有一个线程执行该方法或该代码段。线程锁只在同一JVM中有效果,因为线程锁的实现在根本上是依靠线程之间共享内存实现的,比如synch...

$firecat利白的代码足迹$ 4481

IPCP(IP Control Protocol,IP控制协议)

IPCP(IP Control Protocol,IP控制协议)

天赐好车的博客 754

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

【Big Data 每日一题20181109】分布式锁的作用及实现(Redis)

前言 分布式锁一般有三种实现方式:1. 数据库乐观锁;2. 基于Redis的分布式锁;3. 基于ZooKeeper的分布式锁。本篇博客将介绍第二种方式,基于Redis实现分布式锁。虽然网上已经有各种介绍Redis分布式锁实现的博客,然而他们的实现却有着各种各样的问题,为了避免误人子弟,本篇博客将详细介绍如何正确地实现Redis分布式锁。 可靠性 首先,为了确保分布式锁可用,我们至少要确保锁的...

tianyeshiye 190

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

redis实现分布式锁

通过流程图也可以看到,若要使用redis实现分布式锁,会存在一些性能问题,因为在等待锁的过程中会一直自旋,周而复始的去判断是否有锁资源,如果要用高性能的分布式锁,还是需要用zookeeper,因为zookeeper天生就是用来做分布式锁的;

叶新东老师的博客 843

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

六.Redis极简入门-Redis实现分布式锁原理

老鸟飞过,学习使用,欢迎交流 理解分布式锁 为什么要分布式锁 在并发场景中,我们可以使用加锁的手段来保证业务方法或代码的原子性操作,从而防止数据被并发修改引发安全问题,在单体应用中我们可以使用互斥锁如: synchronized 同步代码块 或者 Lock锁来实现,如图: 但是在集群/分布式应用中单纯的互斥锁是不能保证多个节点中对同一个数据的原性操作的,如图: 集群模式中,每个服务都加了锁但是只能锁住自己,每个服务做库存做扣减操作,当库存都剩1的时候,三个服务并发减库存可能会导致库存减到 -2 出现线程

墨家巨子@俏如来 1万+

Redis-实现分布式锁

如实使用Redis实现分布式锁

qq_36481984的博客 1012

分布式锁:Zookeeper 和 Redis 实现方案对比分析

在分布式系统开发中,分布式锁是一个至关重要的概念,也是经常被讨论的技术点。尤其是在处理多个进程或线程同时访问共享资源的场景时,选择合适的分布式锁实现方案显得尤为关键。今天我们就来深入探讨一下实现分布式锁的两种常见方案:Zookeeper 和 Redis,并分析它们各自的优缺点。

m0_57836225的博客 1466

在 Go 语言中使用 Redis 实现分布式锁

定义一个分布式锁结构体,包含 Redis 客户端、锁的键名、过期时间等字段。import ("time"key string在 Go 语言中,可以使用 Redis 的 SETNX 命令和 EXPIRE 命令来实现分布式锁。通过定义分布式锁结构体,并实现获取锁和释放锁的方法,可以方便地在分布式系统中使用分布式锁。在使用分布式锁时,需要注意锁的过期时间、错误处理和分布式环境下的时钟同步等问题。

m0_57836225的博客 1050

Redis分布式锁

分布式锁是一种在分布式系统中用于确保多个节点或进程在任何给定时间点,只有一个能够执行特定资源或任务的同步机制。在分布式系统中,不同的节点可能需要访问共享资源,为了防止多个节点同时修改资源造成数据不一致或冲突,就需要使用分布式锁来保证在任一时刻,只有一个节点可以访问该资源。简单来说就是满足分布式系统或者集群模式下多进程可见并互斥的锁分布式锁的特性:互斥性:在任意时刻,只有一个进程可以持有锁。安全性:持有锁的进程能够保证在它释放锁之前,其他进程不能获取同一把锁高性能。

m0_73598900的博客 843
上一篇: 最容易理解的Consistent Hashing讲解(一致性哈希算法使用场景及原理)
下一篇: 设计模式集锦
LiQiyaoo
博客等级 码龄11年 337粉丝 206原创
评论 50
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值