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.rhkb.cn/news/457891.html

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

相关文章

架构师备考-数据库设计、实施和维护

数据库设计 数据库设计的任务是针对一个给定的应用环境,在给定的硬件环境和操作系统及数据库管理系统等软件环境下,创建一个性能良好的数据库模式,建立数据库及其应用系统,使之能有效地存储和管理数据,满足各类用户的需…

Node.js 模块化

1. 介绍 1.1 什么是模块化与模块 ? 将一个复杂的程序文件依据一定规则(规范)拆分成多个文件的过程称之为 模块化其中拆分出的 每个文件就是一个模块 ,模块的内部数据是私有的,不过模块可以暴露内部数据以便其他模块使用 1.2 什…

Stable Diffusion视频插件Ebsynth Utility使用方法

在Stable Diffusion中安装完Ebsynth Utility后,就可以开始试用了。 启动Stable Diffusion后,出面画面: 1、步骤1:视频分帧及生成蒙板帧 填入工程目录,选择上传所用的视频文件:注意对目录命名的要求-不能有…

尽管加密货币被禁,中国仍是比特币挖矿巨头!不过主导地位正在转向美国?

尽管中国政府全面禁止了加密货币交易和挖矿活动,但中国依然在比特币挖矿领域保持着全球领先地位。然而,随着美国在该领域的快速崛起,中国在比特币挖矿主导地位方面正面临来自美国的强劲竞争。根据最新的市场数据和行业分析,中国的…

华为:高级ACL 特定ip访问特定ip命令

网络拓扑图: 网络环境: 全网互通即可 1.创建一个名为test的高级ACL acl name test advance 2.添加规则 ##拒绝所有ip访问 rule 10 deny ip source any destination 192.168.1.10 0.0.0.0 只允许特定ip访问特定ip rule 5 permit ip source 192.168.2.10…

计算机网络:网络层 —— IPv4 地址的应用规划

文章目录 IPv4地址的应用规划定长的子网掩码变长的子网掩码 IPv4地址的应用规划 IPv4地址的应用规划是指将给定的 IPv4地址块 (或分类网络)划分成若干个更小的地址块(或子网),并将这些地址块(或子网)分配给互联网中的不同网络,进而可以给各网络中的主机…

Oracle CONNECT BY、PRIOR和START WITH关键字详解

Oracle CONNECT BY、PRIOR和START WITH关键字详解 1. 基本概念2. 数据示例3. SQL示例3.1. 查询所有员工及其上级3.2. 显示层次结构3.3. 查询特定员工的子级 4. 结论 在Oracle数据库中,CONNECT BY、PRIOR和START WITH关键字主要用于处理层次结构数据,例如…

web3对象如何连接以太网络节点

实例化web3对象 当我们实例化web3对象,我们一般开始用本地址,如下 import Web3 from web3 var web3 new Web3(Web3.givenProvider || ws://localhost:5173)我们要和以太网进行交互,所以我们要将’ws://localhost:5173’的本地地址换成以太…

循序渐进丨openGauss / MogDB 数据库内存占用相关SQL

一、内存总体分布 数据库总体内存使用分布 select * from gs_total_memory_detail; 当dynamic_used_memory大于max_dynamic_memory就会报内存不足;如果此时dynamic_used_memory小于max_dynamic_memory,而dynamic_peak_memory大于max_dynamic_memory表…

《皮革制作与环保科技》是什么级别的期刊?是正规期刊吗?能评职称吗?

​问题解答 问:《皮革制作与环保科技》是不是核心期刊? 答:不是,是知网收录的正规学术期刊。 问:《皮革制作与环保科技》级别? 答:国家级。主管单位:中国轻工业联合会 …

【书籍推荐】使用 MATLAB 算法进行合成孔径雷达信号处理【附MATLAB代码】

简介 介绍了合成孔径雷达 (SAR) 波前重建信号理论及其数字实现的最新分析。随着快速计算和数字信息处理技术的出现,SAR 技术变得更加强大和准确。使用 MATLAB 算法进行合成孔径雷达信号处理解决了这些最新发展问题,提供了对 SAR …

【随手笔记】远程升级之如何平衡下载包大小与速率?

1. 远程升级基本信息 使用NB_BC26模组,通过AT指令使用TCP的协议与公司后台交互升级的固件为BIN文件,使用原始固件包升级,未使用差分方式原始固件包有110K,大小左右,固件的存储为外置的FLASH W25Q16,w25q16最小存储单位为页&#…

git命令笔记(速查速查)

git命令功能总结 1.创建git的本地仓库2. 配置本地仓库(name和email地址)3. 工作区、版本库、暂存区、对象区3.1 add, commit3.2 打印提交日志3.2 修改文件 4.版本回退(git reset)5. 撤销修改(在push之前撤销)6.删除版本库中的文件…

C++——string的模拟实现(上)

目录 引言 成员变量 1.基本框架 成员函数 1.构造函数和析构函数 2.拷贝构造函数 3.容量操作函数 3.1 有效长度和容量大小 3.2 容量操作 3.3 访问操作 (1)operator[]函数 (2)iterator迭代器 3.4 修改操作 (1)push_back()和append() (2)operator函数 引言 在 C—…

微信小程序版本更新管理——实现自动更新

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

查找总价格为目标值的两个商品----双指针算法

一&#xff1a;题目描述 题目链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 二&#xff1a;算法原理 三&#xff1a;代码编写 vector<int> twoSum(vector<int>& price, int target) {vector<int> ret;int left 0, right price.size()-…

银河麒麟相关

最近安装了银河麒麟server版本&#xff0c;整理下遇到的一些小问题 1、vmware安装Kylin-Server-V10-SP3-General-Release-2303-X86_64虚拟机完成后&#xff0c;桌面窗口很小&#xff0c;安装vmwaretools后解决&#xff0c;下载地址http://softwareupdate.vmware.com/cds/vmw-de…

centos安装指定版本的jenkins

打开jenkins镜像包官网&#xff0c;找到自己想要安装的版本&#xff0c;官网地址&#xff1a;https://mirrors.tuna.tsinghua.edu.cn/jenkins/redhat-stable 下载指定版本安装包&#xff1a; wget https://mirrors.tuna.tsinghua.edu.cn/jenkins/redhat-stable/jenkins-2.452.…

Vue3学习:汇率计算器案例中event.target与event.currentTarget比较

今天从一本vue.js书中学习了《汇率计算器》的案例&#xff0c;这个案例的效果如下&#xff1a; 案例可以查询人民币、日元、港元、美元、欧元之间的汇率关系&#xff0c;代码中定义了一个汇率表rate&#xff0c;包含了每种货币对其他5种货币的汇率。其中还有一个功能是点击下方…

从零到一:如何使用直播美颜SDK开发视频美颜平台

今天&#xff0c;小编将为大家详细讲解如何从零开始&#xff0c;利用直播美颜SDK进行开发视频美颜平台。 一、了解直播美颜SDK 选择合适的SDK是开发视频美颜平台的第一步&#xff0c;市场上有多种SDK可供选择。选择时应考虑SDK的功能、性能、稳定性以及开发者社区的支持。 二…