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();}
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JavaScript part2

一.前言 前面我们讲了一下js的基础语法,但是这些还是远远不够的,我们要想操作标签,实现一个动态且好看的页面,就得学会BOM和DOM,这些都是浏览器和页面的,这样我们才能实现一个好看的页面 二.BOM对象 BOM…

Radar Fields: Frequency-Space Neural Scene Representations for FMCW Radar 笔记

Code 主要思想 文章提出了一种新的神经场表示方法——Radar Fields,用于从FMCW(调频连续波)雷达数据中恢复场景几何信息。与以往的依赖于光学成像(如RGB相机和LiDAR)的神经场方法不同,该研究利用了雷达的…

高级网络互联技术:AS3001与AS3000的路由交换方案

✅作者简介:2022年博客新星 第八。热爱国学的Java后端开发者,修心和技术同步精进。 🍎个人主页:Java Fans的博客 🍊个人信条:不迁怒,不贰过。小知识,大智慧。 💞当前专栏…

基于SSM的智能养生平台管理系统源码带本地搭建教程

技术栈与架构 技术框架:采用SSM(Spring Spring MVC MyBatis)作为后端开发框架,结合前端技术栈layui、JSP、Bootstrap与jQuery,以及数据库MySQL 5.7,共同构建项目。 运行环境:项目在JDK 8环境…

HarmonyOS 5.0应用开发——应用打包HAP、HAR、HSP

【高心星出品】 目录 应用打包HAP、HAR、HSPModule类型HAPHAR创建HAR建立依赖HAR共享内容 HSP创建HSP建立依赖同上HSP共享内容同上 HAR VS HSP 应用打包HAP、HAR、HSP 一个应用通常会包含多种功能,将不同的功能特性按模块来划分和管理是一种良好的设计方式。在开发…

【mysql】4-2. MySQL存储结构

MySQL存储结构 1 什么是表空间⽂件? 解答问题 表空间⽂件是⽤来存储表中数据的⽂件,表空间⽂件的⼤⼩由存储的数据多少决定,不同的表空间⽂件存储数据的种类也有所不同,在MySQL中表空间分为五类,包括:系统…

Python | Leetcode Python题解之第514题自由之路

题目: 题解: Test "godding" target "d"i 0left i lc 0 right i rc 0while Test[left] ! target:left - 1lc 1if left -1:left len(Test) - 1while Test[right] ! target:right 1rc 1if right len(Test):right 0prin…

vue3报错:找不到模块“element-plus”或其相应的类型说明

1.问题复现 2.首先去检查一下package.json中是否安装了element-plus 3.存在,就是另一个问题,模块没有被导出来 a.此时需要建立一个.d.ts文件(在package.json同级目录下) 4.写入代码保存,即可解决报错问题 declare mo…

安卓在windows连不上fastboot问题记录

fastboot在windows连不上fastboot 前提是android studio安装 google usb driver 搜索设备管理器 插拔几次找安卓设备 在其他设备 或者串行总线设备会出现安卓 右键更新驱动 下一步下一步然后可以了

计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-21

计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-21 目录 文章目录 计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-21目录1. The Fair Language Model Paradox摘要研究背景问题与挑战如何解决创新点算法模型实验效果重要数据与结论推荐阅读指数&…

海外媒体发稿:如何打造媒体发稿策略

新闻媒体的发稿推广策略对于提升品牌知名度、吸引流量以及增加收入非常重要。本文将介绍一套在21天内打造爆款新闻媒体发稿推广策略的方法。 第一天至第七天:明确目标和定位 在这个阶段,你需要明确你的目标和定位,以便为你的新闻媒体建立一个…

群晖系统基本命令

切换超级管理员 sudo -i 查询系统 运行的所有服务 synoservicecfg --list 启动服务命令(该命令需要使用超级管理员) #老版本群晖使用synoservice命令 synoservice --start 服务名称#新版本群晖使用systemctl命令 systemctl start 服务名称 synoservice所管理的服务配置文…

Spring Cloud微服务

Spring Cloud 是一个专注于微服务架构的一站式解决方案,它通过整合多个优秀的开源框架和工具,为开发者提供了构建、管理和维护微服务系统所需的全方位支持。以下是关于 Spring Cloud 微服务的详细介绍: 基本概念 微服务架构:微服务…

Maven的依赖

一、依赖的基本配置 根元素project下的dependencies可以包含多个 dependence元素,以声明多个依赖。每个依赖都应 该包含以下元素: 1. groupId, artifactId, version : 依赖的基本坐标, 对于任何⼀个依赖来说,基本坐标是最…

【GIT】Visual Studio 中 Git 界面中, 重置 和 还原

在 Visual Studio 的 Git 界面中,“重置” 和 “还原” 是两个常用的 Git 操作。它们的主要区别在于应用场景和影响范围。 1. 重置(Reset) 重置用于更改当前分支的提交历史,通常用于撤销或删除某些提交。重置操作可能会更改 Git…

Flink CDC系列之:调研应用Flink CDC将 ELT 从 MySQL 流式传输到 StarRocks方案

Flink CDC系列之:调研应用Flink CDC将 ELT 从 MySQL 流式传输到 StarRocks方案 准备准备 Flink Standalone 集群准备 docker compose为 MySQL 准备记录使用 Flink CDC CLI 提交作业 同步架构和数据更改路由变更清理 本教程将展示如何使用 Flink CDC 快速构建从 MySQ…

[Ansible实践笔记]自动化运维工具Ansible(二):Ansible的playbook及角色

Ansible playbook(剧本) 详情请参考[Ansible实践笔记]自动化运维工具Ansible(一):初探ansible&ansible的点对点模式 文章目录 Ansible playbook(剧本)介绍核心字段环境配置案例&#xff1…

React--》掌握Valtio让状态管理变得轻松优雅

Valtio采用了代理模式,使状态管理变得更加直观和易于使用,同时能够与React等框架无缝集成,本文将深入探讨Valtio的核心概念、使用场景以及其在提升应用性能中的重要作用,帮助你掌握这一强大工具,从而提升开发效率和用户…

【Go语言】

type关键字的用法 定义结构体定义接口定义类型别名类型定义类型判断 别名实际上是为了更好地理解代码/ 这里要分点进行记录 使用传值的例子,当两个类型不一样需要进行类型转换 type Myint int // 自定义类型,基于已有的类型自定义一个类型type Myin…

用kali入侵 DarkHole_2测试

进入kali系统调出root交互式界面 netdiscover -r 000.000.000.000/24 -------局域网探测IP工具 nmap 设备端口扫描 发现两个攻击点一个是80端口的Http 一个是22端口的ssh 发现有许多GIT文件 可能会出现git源码泄露 使用githack URL 命令还原git源文件 打开面板控制命令行 输入…