Redis 线程控制 总结

前言


 相关系列

  • 《Redis & 目录》(持续更新)
  • 《Redis & 线程控制 & 源码》(学习过程/多有漏误/仅作参考/不再更新)
  • 《Redis & 线程控制 & 总结》(学习总结/最新最准/持续更新)
  • 《Redis & 线程控制 & 问题》(学习解答/持续更新)
     

 参考文献

  • 《Redis分布式锁》
     
     

概述


    Redisson基于Redis提供了多项适用于分布式环境的线程控制功能。Redisson的本质是一套由Redis官方提供的Java版API,其提供了包括线程控制工具在内的多项功能,支持在分布式环境中开箱即用。

    Redisson锁支持自动释放。Redisson锁既可以像常规锁定义一样被无限持有至手动释放,也支持在超出指定时间后自动释放,而如此设计的目的则是为了避免客户端断线而导致锁永远无法被解锁的情况发生。此外即使我们对锁进行的是无限加锁,Redisson也会为该锁设置30秒的默认存活时间,并在确保锁依然被正常持有的情况下为之定时延续,从而得以彻底避免死锁现象。
 
 

可重入锁


public void lock() {
    // ---- 获取(重入)锁。
    RLock rLock = redissonClient.getLock("lock");
    // ---- 无限加锁。
    rLock.lock();
    // ---- 有限加锁。
    // rLock.lock(30L, TimeUnit.SECONDS);
    try {
        // ---- 逻辑操作。
    } finally {
        rLock.unlock();
    }
}

    Redisson使用哈希类型来记录可重入锁信息。在Redisson的设计&实现中,其会使用哈希类型来记录可重入锁的数据信息,目的是为了将加锁线程标记/锁重入次数分别作为键/值好一次性保存。Redisson会为欲加锁可重入锁的线程生成UUID以作为唯一标记,以确保只有加锁线程才能执行重入/解锁。可重入锁的本质是独占锁,因此虽说哈希类型支持保存多个键/值对,但可重入锁的锁信息中永远只会存在单个键/值对。

在这里插入图片描述

    Redisson会为“无限加锁”的锁(不限于可重入锁)设置默认存活时间。为了避免网络断连而造成死锁,Redisson会为无限加锁的锁设置30秒的默认存活时间。如此一来即使某客户端与Redis中途断连而导致加锁线程未能手动解锁,Redis也能保证在最迟30秒后将该锁自动删除/解锁,从而确保不会出现其它线程永远无法加锁的死锁情况。

    Redisson会为“无限加锁”的锁(不限于可重入锁)续命/续约。Redisson为无限加锁的锁设置默认存活时间这一点带来的最大问题是:如果加锁线程持有锁的时间超过30秒的默认存活时间,那么不就可能出现其它成功加锁相同锁的情况吗?必然此时该锁已被Redis自动删除/解锁了。事实上正常情况下也确实会如此,因此Redisson还支持为无限加锁的锁进行续命/续约来避免该问题。所谓锁续命/续约是指Redisson会为成功无限加锁的锁同步创建负责监控的Watch Dog @ 看门狗线程,当看门狗线程以10秒的频率监控发现锁依然被正常持有时,其便会将之剩余存活时间重置为初始的30秒,直至锁被手动解锁或因为网络断连而无法更新为止。
 
 

可重入公平锁


public void fairLock() {
    // ---- 获取(重入)公平锁。
    RLock rLock = redissonClient.getFairLock("fair:lock");
    // ---- 无限加锁。
    rLock.lock();
    // ---- 有限加锁。
    // rLock.lock(30L, TimeUnit.SECONDS);
    try {
        // ---- 逻辑操作。
    } finally {
        rLock.unlock();
    }
}

    可重入公平锁是可重入锁的公平类型。可重入锁是不公平的,即线程不会按对可重入锁的访问顺序来依次完成加锁,但可重入公平锁却借助FIFO @ 先入先出队列实现了这一点,因为“队列的先入先出特性”及“只允许头部线程加锁的规则”能够保证线程必然会按访问顺序来依次加锁可重入锁。

在这里插入图片描述
 
 

读写锁


public void readLock() {
    RReadWriteLock rReadWriteLock = redissonClient.getReadWriteLock("read:write:lock");
    // ---- 无限加锁。
    rReadWriteLock.readLock().lock();
    // ---- 有限加锁。
    // rReadWriteLock.readLock().lock(30L, TimeUnit.SECONDS);
    try {
        // ---- 逻辑操作。
    } finally {
        rReadWriteLock.readLock().unlock();
    }
}

public void writeLock() {
    RReadWriteLock rReadWriteLock = redissonClient.getReadWriteLock("read:write:lock");
    rReadWriteLock.writeLock().lock();
    // ---- 有限加锁。
    // rReadWriteLock.writeLock().lock(30L, TimeUnit.SECONDS);
    try {
        // ---- 逻辑操作。
    } finally {
        rReadWriteLock.writeLock().unlock();
    }
}

    Redisson会额外记录读写锁当前被持有的锁类型。为了能够知晓读写锁被持有的具体类型,Redisson会将之以mode为键记录在读写锁的哈希中,而代表读/写锁的值则分别为read/write。此外由于读锁是共享锁,会出现被多个线程同时持有的情况。因此与上文所述独占锁仅有单个键/值对的哈希不同,读写锁在读锁被持有时其哈希中可能会存在多个键/值对。

在这里插入图片描述
在这里插入图片描述
    Redisson会独立记录每个读线程的加锁时长。由于读锁支持被多线程同时持有,并且多线程持有读锁的时长也并不一定相同,因此除了会将读线程的UUID存入哈希外,Redisson还会额外以{读写锁键}:读线程UUID:rwlock_timeout:1的格式生成键来记录读线程的具体加锁时长。不过需要注意的是:读线程的加锁时长并不是以值的形式存在的,而是会以键/值对存活时间的形式存在,因此该键/值对的失效就同步意味着该线程对读锁的持有已自动到期。 而如果读线程是无限加锁,那么Redisson便会通过看门狗线程来定时重置其剩余存活时间至30秒…可一个看门狗线程真的能够同时应对这么多无限加锁的读线程吗?这个问题但从数据结构上我并无法获得答案…源码?以后再说吧😁。

在这里插入图片描述
 
 

红锁


public void redLock() {
    RLock rLock1 = redissonClient.getLock("lock:1");
    RLock rLock2 = redissonClient.getLock("lock:2");
    RLock rLock3 = redissonClient.getLock("lock:3");
    // ---- 使用红锁同时加三个锁。
    RLock redLock = redissonClient.getRedLock(rLock1, rLock2, rLock3);
    // ---- 无限加锁。
    redLock.lock();
    // ---- 有限加锁。
    // redLock.lock(30L, TimeUnit.SECONDS);
    try {
        // ---- 逻辑操作。
    } finally {
        redLock.unlock();
    }
}

    红锁的本质是使用多个锁来保护单个资源。我们很容易理解的一点是:锁信息是存在丢失的可能,因为持久化机制/主从同步都无法保证数据完全不丢失。而由于非法解锁可能导致程序出现并发/异常等情况,因此Redisson便设计&提供了红锁来避免这一点。红锁的本质是使用多个锁来保护单个资源,如此一来即使少数锁的信息因为Redis实例的宕机而丢失,其它依然存在的锁信息也一样可以维持锁功能的的正常使用。

在这里插入图片描述

    红锁只在集群中使用才有意义。在单机/主从部署的Redis中使用红锁其实是没有太大意义的,因为无论你使用了多少锁来组成红锁,这些锁的信息也都只会被统一保存在单个Redis实例/主机中,因此锁信息一旦发生丢失往往也是全局性的。但在集群中情况就完全不一样了,由于这些组成红锁的锁会被分散到不同的主节点中保存信息,因此锁信息丢失也仅限于宕机主节点所拥有的部分。

在这里插入图片描述

    红锁已被淘汰。红锁在较新版本的Redisson中已经开始过时,原因正如上文所说是其仅在Redis集群中才有实用意义。而由于现实情况中绝大多数公司的业务体量都无法达到需要搭建Redis集群的程度,因此为了增强红锁的实用范围Redisson便对红锁的概念/实现进行了迭代。在较新的Redisson中,红锁已从单一的锁类型转变为通用的锁特性,即所有的Redis锁实现都默认携带有红锁功能,因此所谓淘汰是指作为单一锁类型的红锁被淘汰。红锁特性的作用表现在当线程试图进行加/解任意类型的锁时,如果要操作的目标Redis实例存在任意形式(主从/集群)的从机,那么其只有当主机中的锁信息被成功同步至从机后才会返回加/解锁成功…该设计变动带来的好处具体如下:

  • 多锁变为单锁,节省了锁信息的内存开销;
  • 锁信息从集群多地保存变为主从多地保存,虽然安全性整体有所降低,但亦保证了足够的体量;
  • 仅集群可用变为主从可用,提升了实用范围;
  • 单一锁类型转为通用锁特性,提升了使用范围。
     
     

联锁


public void multiLock() {
    // ---- 获取三个锁,这三个锁分别用于保护不同的资源。
    RLock rLock1 = redissonClient.getLock("lock:1");
    RLock rLock2 = redissonClient.getLock("lock:2");
    RLock rLock3 = redissonClient.getLock("lock:3");
    // ---- 使用联锁同时加三个锁。
    RLock multiLock = redissonClient.getMultiLock(rLock1, rLock2, rLock3);
    // ---- 无限加锁。
    multiLock.lock();
    // ---- 有限加锁。
    // multiLock.lock(30L, TimeUnit.SECONDS);
    try {
        // ---- 逻辑操作。
    } finally {
        multiLock.unlock();
    }
}

    联锁用于为多锁加锁提供“伪”原子性保证。所谓“伪”原子性是指在多锁加锁会连续执行,中间不会出现有其他Redis指令插队的情况。那为什么说是“伪”原子性呢?这是因为原子性存在“一同成功/失败”的概念规则,但上述任意锁的失败既不会造成回滚,也不后影响后续锁的加锁,因此便被成为“伪”原子性。联锁是一项非常实用的功能,因为多锁加锁是很容易因为顺序原因而出现死锁问题的…例如下文代码所示,而联锁的“伪原子性”则很好的避免了这点。

public void method1() {
    RLock rLock1 = redissonClient.getLock("lock:1");
    rLock1.lock();
    RLock rLock2 = redissonClient.getLock("lock:2");
    rLock2.lock();
    try {
        // ---- 逻辑操作。
    } finally {
        rLock2.unlock();
        rLock1.unlock();
    }
}
// ---- 两个方法都要加锁1/2,但两者的顺序却不一样。这就可能出现线程A/B分别成功
// 加锁锁1/2然后相互等待锁2/1的死锁情况。

public void method2() {
    RLock rLock2 = redissonClient.getLock("lock:2");
    rLock2.lock();
    RLock rLock1 = redissonClient.getLock("lock:1");
    rLock1.lock();
    try {
        // ---- 逻辑操作。
    } finally {
        rLock1.unlock();
        rLock2.unlock();
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/902859.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

https://huggingface.co/上的模型无法用linux服务器clone怎么办(只需要稍微改一下网址,就可以切换到镜像下载)

问题描述: 在ubuntu系统上,使用如下命令,克隆仓库,报无法访问错误: git clone https://huggingface.co/distilbert/distilroberta-base通用解决方案: 把下面部分更换: https://huggingface.…

Scrapy框架原理与使用流程

一.Scrapy框架特点 框架(Framework)是一种软件设计方法,它提供了一套预先定义的组件和约定,帮助开发者快速构建应用程序。框架通常包括一组库、工具和约定,它们共同工作以简化开发过程。scrapy框架是python写的 为了爬…

为什么有0.35/Tr这一信号带宽定义

从频域幅值函数可以近似认为这是一个低通滤波器模型,可以采用RC网络模型来处理,根据电路理论计算电压10%到90%所需上升时间,再根据滤波器频域特性计算幅值在-3db处的频率极限,通过两个关系式可以计算出频率极大值和上升时间关系&a…

<<机器学习实战>>15-26节笔记:逻辑回归参数估计、梯度下降及优化、模型评价指标

梯度下降缺点:有可能有鞍点(如果不是凸函数的时候),不一定能找到最小值解决方法:随机梯度下降(选一条数据)和小批量梯度下降(选几条数据这两个解决方法又会带来新问题,比…

51单片机完全学习——LCD1602液晶显示屏

一、数据手册解读 通过看数据手册我们需要知道,这个屏幕每个引脚的定义以及如何进行发送和接收。通过下面这张图我们就可以知道,这些引脚和我们的编程是有关的,需要注意的是,这里我们在接线的时候,一定要把DB0-DB7接到…

变流升压一体机:能源领域的新兴力量与优秀品牌

在当今能源转型的大背景下,变流升压一体机作为一种创新型的电力设备,正逐渐成为新能源领域的关键角色。 变流升压一体机是一种综合性很强的光伏箱式变电站设备,它将储能变流器、升压变压器、高压环网柜、低压配电箱等多种设备集成在一个集装箱…

LeetCode.冗余连接(并查集以及广度优先搜索)

684.冗余连接| 传送门:. - 力扣(LeetCode) 树可以看成是一个连通且 无环 的 无向 图。 给定往一棵 n 个节点 (节点值 1~n) 的树中添加一条边后的图。添加的边的两个顶点包含在 1 到 n 中间,且这条附加的边不属于树中…

上线 24 小时,爆了!

产研团队(兼客服)已爆单🔥🚀💥!(bushi) 在此由衷感谢各位小伙伴的信任🤩! 还没有试用的小伙伴赶紧去围观👇️👇️👇️ …

高效数据集成案例:从聚水潭·奇门到MySQL

聚水潭奇门数据集成到MySQL的技术案例分享 在企业信息化建设中,数据集成是实现业务流程自动化和数据统一管理的关键环节。本文将分享一个具体的系统对接集成案例:如何将聚水潭奇门平台上的销售出库单数据高效、可靠地集成到MySQL数据库中,以…

AUTOSAR-Com模块

COM 文章目录 COMCOM 基础介绍COM主要功能AUTOSAR COM 模块 发送模型Signal 信号/信号组发送信号属性—Triggered属性Pending属性信号的初始化信号的对齐方式(大小端)信号的收发发送接收 字节序转换和符号扩展信号的过滤机制过滤处理信号传输模式信号流和…

【十进制转十六进制数】

【十进制转十六进制数】 C语言版本C 版本Java版本Python版本 💐The Begin💐点点关注,收藏不迷路💐 从键盘接收一个整数,编程实现将其转换成十六进制数。 输入 一个整数 输出 十六进制数 样例输入 100样例输出 6…

day01-ElasticStack+Kibana

ElasticStack-数据库 #官网https://www.elastic.co/cn/ #下载7.17版环境准备 主机名IP系统版本VMware版本elk110.0.0.91Ubuntu 22.04.417.5.1elk210.0.0.92Ubuntu 22.04.417.5.1elk310.0.0.93Ubuntu 22.04.417.5.1 单机部署ES 1.下载ES软件包,放到/usr/local下 […

HTML3D旋转相册

文章目录 序号目录1HTML满屏跳动的爱心(可写字)2HTML五彩缤纷的爱心3HTML满屏漂浮爱心4HTML情人节快乐

react18中react-thunk实现公共数据仓库的异步操作

redux及react-redux都只能实现数据的同步修改更新,有点类似于vue中的mutation,只能做同步操作,异步的话不用actions来实现。由于在项目始终不可避免要实现的异步数据的更新,这明显不够用了。是时候引入我们的异步中间件redux-thun…

计算机组成原理笔记9(指令系统,立即寻址,直接寻址,间接寻址.....)

指令操作码 操作码的位数决定了不同功能指令的多少,位数越多,所能表示的操作功能就越丰富。指令的操作码通常有两种编码格式: 定长操作码 定长操作码对于简化硬件设计,减少指令译码时间非常有利,例如IBM370指令系统&a…

Matlab 火焰识别技术

课题介绍 森林承担着为人类提供氧气以及回收二氧化碳等废弃气体的作用,森林保护显得尤其重要。但是每年由于火灾引起的事故不计其数,造成重大的损失。如果有一款监测软件,从硬件处获得的图像中监测是否有火焰,从而报警&#xff0…

uv: 一个统一的Python包管理工具

uv是由Astral公司开发的一个极其快速的Python包管理器,完全用Rust编写。它最初在2月份发布,作为pip工作流的替代品。现在,uv已经扩展成为一个端到端的解决方案,可以管理Python项目、命令行工具、单文件脚本,甚至Python本身。可以说,uv就像是Python界的Cargo:一个快速、可靠、易…

XQT_UI 组件|03 |加载组件 XQtLoading

XQtLoading 使用文档 简介 XQtLoading 是一个自定义的加载动画组件,旨在为用户提供可配置的旋转花瓣动画效果。它可以在应用程序中用于指示加载状态,提升用户体验。 特征 可配置性:用户可以根据需求调整旋转周期、缩放周期、最大/最小缩放…

置换环模板题E - Permute K times 2

输入样本 1 6 3 5 6 3 1 2 4样本输出 1 6 1 3 2 4 5每次操作后, P P P 都会发生如下变化: 第一次操作后, P P P 为 ( 2 , 4 , 3 , 5 , 6 , 1 ) (2,4,3,5,6,1) (2,4,3,5,6,1) 。第二次操作后, P P P 为 ( 4 , 5 , 3 , 6 , …

溪源飨提高免疫力治未病:硒+辅酶Q10强力组合

上周我和女友在亲友的见证下举行了庄重的订婚仪式。我和女友是经朋友介绍才认识的,认识时间并不算长。第一次见面,彼此就被对方深深地吸引了,真可谓一见钟情。我喜欢她那恬静的美,难以忘怀她那散发着迷人气息的双眸;她…