Redisson分布式锁全解析:从基础到红锁,锁定高并发解决方案

1. 介绍Redisson和分布式锁的概念

1.1 Redisson简介

Redisson是一个在Redis的基础上实现的Java驻内存数据网格(In-Memory Data Grid, IMDG)。它不仅提供了对分布式和可伸缩数据结构的支持,还提供了多种分布式服务,包括但不限于分布式锁、集合、映射、计数器、发布/订阅消息等。Redisson通过利用Redis键的atomic性质,实现了分布式锁等高级功能。

1.2 分布式锁的重要性

在分布式系统中,多个进程可能会同时访问相同的资源,如数据库记录或文件。如果不适当管理,就会导致数据不一致或竞态条件。分布式锁是控制分布式系统中多个节点共享资源同步访问的一种机制。它们帮助维护跨节点的资源访问顺序,保持数据的一致性和完整性。

1.3 Redisson在分布式锁中的角色

Redisson将Redis的高性能和高可用性引入了分布式锁的实现。利用Redis强大的命令集,Redisson实施锁操作成为可能,并且这些锁操作是原子的,这意味着Redisson提供了一种可靠和高效的方式来实施分布式锁机制。

2. 可重入锁(Reentrant Lock)

2.1 可重入锁的概述

可重入锁是指同一个线程可以多次获得同一把锁。这种类型的锁可以避免死锁的发生,因为它允许同一线程在没有释放锁的情况下多次获得锁。这在递归函数或者一系列相互调用的函数需要访问同一个资源时特别有用。

2.2 在Redisson中实现可重入锁

Redisson实现了一个分布式的可重入锁RLock,它支持自动续租,保证了锁的持有者在宕机或无响应时,锁会自动释放。它通过利用Redis的特性,有效地完成锁定和解锁操作。

2.3 可重入锁的实际应用场景

可重入锁非常适合那些需要连续几次访问一个资源的场景。例如,一个电商平台的订单创建过程中,从验证库存到最终下单可能需要多次进行资源锁定,可重入锁可以确保整个过程的同步执行。

2.4 代码实现和示例

import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;public class ReentrantLockExample {public static void main(String[] args) {Config config = new Config();config.useClusterServers().addNodeAddress("redis://127.0.0.1:7181");RedissonClient redisson = Redisson.create(config);RLock lock = redisson.getLock("anyLock");try {// 支持自动续租lock.lock();// 处理业务逻辑} finally {lock.unlock();}}
}

在上面的例子中,我们创建了Redisson客户端,并且获取了一个分布式锁anyLock。在锁定资源期间,如果处理业务逻辑的时间超过了锁的持续时间,Redisson会自动续租,直到业务逻辑处理完成,随后释放锁。这确保了在发生异常情况下,锁将不会被永久持有。

3. 公平锁(Fair Lock)

3.1 公平锁与非公平锁的区别

公平锁是一种严格按照请求锁的顺序来分配锁的机制,即先来先得。对比之下,非公平锁则可能允许后请求的进程先获得锁。非公平锁可能会导致某些线程饥饿,但是通常其性能高于公平锁,因为它减少了线程之间的切换。

3.2 Redisson的公平锁实现

Redisson提供了RFairLock,一个可重入的公平锁实现。它保证了最长等待的线程最优先获取锁。这是通过在Redis中维护一个请求队列来实现的,确保了锁分配的公平性。

3.3 使用公平锁解决问题的示例

公平锁适用于需要保证处理顺序的场景,如打印队列、线程池任务执行顺序等。它可以避免"饥饿"情况,保证系统处理的有序性和公平性。

3.4 代码实现和示例

import org.redisson.Redisson;
import org.redisson.api.RFairLock;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;public class FairLockExample {public static void main(String[] args) {Config config = new Config();config.useClusterServers().addNodeAddress("redis://127.0.0.1:7181");RedissonClient redisson = Redisson.create(config);RFairLock fairLock = redisson.getFairLock("anyFairLock");try {// 尝试加锁,最多等待100秒,上锁以后10秒自动解锁boolean res = fairLock.tryLock(100, 10, TimeUnit.SECONDS);if (res) {// 处理业务逻辑}} catch (InterruptedException e) {e.printStackTrace();} finally {fairLock.unlock();}}
}

在上面的示例中,我们使用了Redisson的RFairLock来创建一个公平锁,确保线程按照请求锁的顺序来获得锁定资源的权限。尝试锁定时,我们设置了最大等待时间和锁的持有时间,以避免可能的死锁。

4. 联锁(MultiLock)

4.1 联锁的工作原理

联锁是一种同步机制,用于同时获取多个锁。在分布式系统中,当需要对多个独立资源进行操作时,联锁确保所有的资源都被锁定,以进行安全的原子操作。

4.2 如何使用Redisson实现联锁

Redisson通过MultiLock类提供了联锁的实现。你可以将多个RLock对象传入MultiLock,它会同时锁定所有的锁。只有当所有的锁都被成功获取,线程才能继续执行。

4.3 联锁的使用场景

联锁在需要执行跨多个资源的复合操作时非常有用,例如,在两个账户间进行资金转账时,需要同时锁定两个账户的资源。

4.4 代码实现和示例

import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.redisson.api.MultiLock;import java.util.concurrent.TimeUnit;public class MultiLockExample {public static void main(String[] args) {Config config = new Config();config.useClusterServers().addNodeAddress("redis://127.0.0.1:7181");RedissonClient redisson = Redisson.create(config);RLock lock1 = redisson.getLock("lock1");RLock lock2 = redisson.getLock("lock2");RLock lock3 = redisson.getLock("lock3");MultiLock multiLock = new MultiLock(lock1, lock2, lock3);try {// 尝试加锁,最多等待100秒,上锁以后10秒自动解锁boolean res = multiLock.tryLock(100, 10, TimeUnit.SECONDS);if (res) {// 处理跨多个资源的复合操作}} catch (InterruptedException e) {e.printStackTrace();} finally {multiLock.unlock();}}
}

在上面的代码中,我们创建了一个联锁,它会组合三个单独的锁。只有当这三个锁都成功被获取时,才会执行后续的复合操作。这保证了操作的原子性。

5. 红锁(RedLock)

5.1 了解红锁算法

红锁(RedLock)是一种在多个独立的Redis节点上提供分布式锁的算法。它由Redis的创造者Antirez提出,旨在通过在多个节点上使用锁来提高容错性。如果单个节点宕机,使用RedLock算法的系统仍能保持正常运作。

5.2 Redisson中的红锁应用

在Redisson中,RedLock算法被用作确保多个Redis节点间互斥操作的一种方式。通过在多个节点上加锁,RedLock使得系统更加健壮,能够抵御单点故障。

5.3 红锁的实战演示

红锁适用于需要高可用性和高可靠性锁的场景。特别是当系统部署在可能会出现网络分区或者节点故障的环境中时,红锁提供了一种更安全的锁策略。

5.4 代码实现和示例

import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.redisson.RedissonRedLock;import java.util.concurrent.TimeUnit;public class RedLockExample {public static void main(String[] args) {Config config1 = new Config();config1.useSingleServer().setAddress("redis://127.0.0.1:7181");RedissonClient redisson1 = Redisson.create(config1);Config config2 = new Config();config2.useSingleServer().setAddress("redis://127.0.0.1:7182");RedissonClient redisson2 = Redisson.create(config2);Config config3 = new Config();config3.useSingleServer().setAddress("redis://127.0.0.1:7183");RedissonClient redisson3 = Redisson.create(config3);RLock lock1 = redisson1.getLock("lock");RLock lock2 = redisson2.getLock("lock");RLock lock3 = redisson3.getLock("lock");RedissonRedLock redLock = new RedissonRedLock(lock1, lock2, lock3);try {// 尝试加锁,最多等待100秒,上锁以后10秒自动解锁boolean res = redLock.tryLock(100, 10, TimeUnit.SECONDS);if (res) {// 执行任务}} catch (InterruptedException e) {e.printStackTrace();} finally {redLock.unlock();}}
}

在以上示例中,我们通过连接到三个不同的Redis服务器,创建了三个RLock对象,并将它们组合成一个RedissonRedLock对象。这帮助我们在多个节点间实现了互斥,提高了分布式环境下的数据一致性和系统的容错性。

6. 读写锁(ReadWriteLock)

6.1 读写锁的必要性和原理

读写锁是一种支持并发读取而在写入时需要排它的锁机制。这种锁允许多个读取者同时访问资源,但在写入者访问时,所有读取者和其他写入者都必须等待。这大大提高了在读多写少场景下的性能。

6.2 Redisson的读写锁特性

Redisson实现的RReadWriteLock提供了一个读写锁的分布式实现,它保证了当有线程持有写锁时,所有的读锁和其他写锁都将等待。

6.3 在实际项目中应用读写锁

在诸如电子商务网站的商品详情页面,读操作远多于写操作的场景中,读写锁可以有效地提升性能和吞吐量。

6.4 代码实现和示例

import org.redisson.Redisson;
import org.redisson.api.RReadWriteLock;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;import java.util.concurrent.TimeUnit;public class ReadWriteLockExample {public static void main(String[] args) {Config config = new Config();config.useClusterServers().addNodeAddress("redis://127.0.0.1:7181");RedissonClient redisson = Redisson.create(config);RReadWriteLock rwlock = redisson.getReadWriteLock("anyRWLock");RLock readLock = rwlock.readLock();RLock writeLock = rwlock.writeLock();// 获取读锁readLock.lock();try {// 执行读取操作} finally {readLock.unlock();}// 获取写锁try {boolean res = writeLock.tryLock(100, 10, TimeUnit.SECONDS);if (res) {// 执行写入操作}} catch (InterruptedException e) {e.printStackTrace();} finally {writeLock.unlock();}}
}

在这个例子中,我们使用Redisson的RReadWriteLock来分别获取读锁和写锁。读锁可以被多个线程同时持有,而写锁则保证了独占性,直到释放后其他读写操作才能继续进行。

7. 信号量(Semaphore)

7.1 信号量的基本概念

信号量是一个计数器,用来控制多个线程对共享资源的访问。它主要用于实现资源的并发访问控制,并且可以是二进制的(即互斥锁)或者可以拥有多个单位。

7.2 使用Redisson实现分布式信号量

Redisson的分布式信号量RSemaphore允许在多个服务间共享信号量的状态,提供了一种跨进程或跨服务器同步资源访问的方式。

7.3 分布式信号量的应用案例

分布式信号量非常适用于限制对某一资源访问的并发数,比如限制并发访问数据库的线程数量,或者在微服务架构中限制对某个服务的并发请求量。

7.4 代码实现和示例

import org.redisson.Redisson;
import org.redisson.api.RSemaphore;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;public class SemaphoreExample {public static void main(String[] args) {Config config = new Config();config.useClusterServers().addNodeAddress("redis://127.0.0.1:7181");RedissonClient redisson = Redisson.create(config);RSemaphore semaphore = redisson.getSemaphore("mySemaphore");try {// 尝试获取一个许可boolean acquired = semaphore.tryAcquire(1, 100, TimeUnit.SECONDS);if (acquired) {// 执行业务逻辑}} catch (InterruptedException e) {Thread.currentThread().interrupt();} finally {// 释放许可semaphore.release();}}
}

上面的代码片段展示了如何使用Redisson的RSemaphore来控制对共享资源的并发访问。在需要访问资源时,线程会尝试从信号量中获取许可,如果成功则继续执行; 完成后释放许可。

8. 可过期性信号量(PermitExpirableSemaphore)

8.1 可过期性信号量介绍

可过期性信号量是一种特殊类型的信号量,它允许线程在一定时间内持有许可,当指定时间过后,许可会自动失效。这对于需要限时访问的资源来说是非常实用的。

8.2 Redisson的可过期性信号量应用

Redisson提供了RPermitExpirableSemaphore类,用于创建和管理可过期性信号量。这允许在分布式系统中实现临时许可的功能,确保资源使用的灵活性和安全性。

8.3 如何在项目中使用可过期性信号量

当我们需要对资源的访问进行时间限制时,比如在线考试系统中对试题的访问,我们可以使用可过期性信号量来控制访问时间。

8.4 代码实现和示例

import org.redisson.Redisson;
import org.redisson.api.RPermitExpirableSemaphore;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;public class PermitExpirableSemaphoreExample {public static void main(String[] args) throws InterruptedException {Config config = new Config();config.useClusterServers().addNodeAddress("redis://127.0.0.1:7181");RedissonClient redisson = Redisson.create(config);RPermitExpirableSemaphore semaphore = redisson.getPermitExpirableSemaphore("mySemaphore");// 获取一个5分钟后过期的许可String permitId = semaphore.acquire(5, TimeUnit.MINUTES);try {// 执行业务逻辑} finally {// 释放许可semaphore.release(permitId);}}
}

在这段代码中,RPermitExpirableSemaphore被用来获取一个可以在5分钟后自动过期的许可。许可的ID用于后续释放该许可时的识别。

9. 闭锁(CountDownLatch)

9.1 闭锁的概念和用途

闭锁(CountDownLatch)是一种同步机制,它允许一个或多个线程等待直到一系列操作在其他线程中完成。一旦这些操作完成,闭锁会放开,等待的线程就可以恢复执行。

9.2 通过Redisson实现分布式闭锁

Redisson通过RCountDownLatch类提供了闭锁的分布式实现。这允许在不同的JVM进程中等待一定事件的发生,并且与传统的CountDownLatch用法类似。

9.3 分布式闭锁在协调任务中的应用

分布式闭锁特别适用于处理分布式系统中的任务协调问题,例如,在一台机器上启动服务前确保必要的几个服务已经在其他机器上启动。

9.4 代码实现和示例

import org.redisson.Redisson;
import org.redisson.api.RCountDownLatch;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;public class CountDownLatchExample {public static void main(String[] args) throws InterruptedException {Config config = new Config();config.useClusterServers().addNodeAddress("redis://127.0.0.1:7181");RedissonClient redisson = Redisson.create(config);RCountDownLatch latch = redisson.getCountDownLatch("anyCountDownLatch");latch.trySetCount(1);// 在另一个线程或JVM中// latch.countDown();// 等待闭锁释放latch.await();// 继续执行后续逻辑}
}

在这段代码里,我们使用了RCountDownLatch来创建一个闭锁,其计数器为1。只有当另一个线程(或在另一个JVM上)调用countDown()方法后,主线程调用的await()方法之后的代码才会执行。

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

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

相关文章

Excel解日期问题

一、日期类型:yyyy/mm/dd **小技巧: (1)快速选中大量数据 鼠标点击要选中的区域的左上角第一个单元格。鼠标拖拽滚动条,找到要选中的区域的最后一行。按住 SHIFT 键,鼠标点击要选中的区域的右下角最后一…

Linux内核--设备驱动(八)网络整理

目录 一、引言 二、网络设备驱动架构 ------>2.1、网络协议接口层 ------------>2.1.1、sk_buff ------>2.2、网络设备接口层 ------------>2.2.1、net_device相关介绍 ------------>2.2.2、中断处理 ------>2.3、源码分析 ------------>2.3.1、…

C#中实现DataGridView数据的优雅Excel之旅(EPPlus)

DataGridView效果图: EXCEL效果图: 代码如下: 首先要引入EPPlus包 可以使用命令行来安装 Install-Package EPPlus 也可以使用NUGet搜索EPPlus来安装 public Homes(){InitializeComponent();ExcelPackage.LicenseContext OfficeOpenXml.LicenseContext…

Unity打开安卓设备不同的设置面板

1,打开安卓设备不同的设置面板,我还贴心的把Android官网的链接放下面了 2,使用也很方便:unity按钮事件上拖这个脚本,注册MyOpenAndroidSettings方法,参数 填 和枚举值相应的数字 // 功能:打开…

Python基础详解三

一,函数的多返回值 def methodReturn():return 1,2x,ymethodReturn() print(x,y) 1 2 二,函数的多种参数使用形式 缺省参数: def method7(name,age,address"淄博"):print("name:"name",age"str(age)&quo…

Golang——IO操作

1. 输入输出的底层原理 终端其实是一个文件(Linux下一切皆文件),相关实例如下: os.Stdin:标准输出的文件实例,类型为*Fileos.Stdout:标准输入的文件实例,类型为*Fileos.Stderr:标准错误输出的文…

出差——蓝桥杯十三届2022国赛大学B组真题

问题分析 该题属于枚举类型&#xff0c;遍历所有情况选出符合条件的即可。因为只需要派两个人&#xff0c;因此采用两层循环遍历每一种情况。 AC_Code #include <bits/stdc.h> using namespace std; string str;//选择的两人 bool ok(){if(str.find("A")!-1…

Colibri for Mac v2.2.0 原生无损音频播放器 激活版

Colibri支持所有流行的无损和有损音频格式的完美清晰的比特完美播放&#xff0c;仅使用微小的计算能力&#xff0c;并提供干净和直观的用户体验。 Colibri在播放音乐时使用极少的计算能力。该应用程序使用最先进的Swift 3编程语言构建&#xff0c;BASS音频引擎作为机器代码捆绑…

java11基础(接口 static关键字)

目录 一. 接口 1. 接口的定义 2. 接口的实现 3. Comparable接口 4. 抽象类和接口的区别 小结 二. static关键字 1. 静态成员变量 2. static 静态方法 3. static静态代码块 格式: 作用: 执行顺序: 三. 接口拓展 default 和 static 一. 接口 如果一个抽象类没有字段…

【氮化镓】GaN功率器件在转换器设计中的挑战

I. 引言(INTRODUCTION) 宽带隙(WBG)器件的重要性: 引言部分首先强调了宽带隙(WBG)器件在高频、高效率电力电子技术中的关键作用。这些器件,包括碳化硅(SiC)和氮化镓(GaN),相较于传统的硅功率器件,具有显著的优势。宽带隙半导体材料的高击穿场强允许设计更薄的漂…

ADS基础教程汇总

目录 ADS基础教程1 - 软件简介ADS基础教程2 - S参数仿真ADS基础教程3 - Data Display WindowADS基础教程4 - Real Time TuningADS基础教程5 - OptimizationADS基础教程6-蒙特卡洛分析ADS基础教程7-Yiled AnalysisADS基础教程8-仿真库加载ADS基础教程9-理想模型和厂商模型实现及…

设计模式——建造者模式(Builder)

建造者模式&#xff08;Builder Pattern&#xff09;是一种对象构建的设计模式&#xff0c;它允许你以一种逐步构建的方式来创建复杂对象。建造者模式通常用于构建具有多个组成部分的对象&#xff0c;并且这些组成部分通常具有不同的构建和表示方式。 建造者模式主要包括以下几…

探索 Python:从初学者到编程达人

Python 是一门多用途的高级编程语言&#xff0c;它具有简单易学、功能丰富的特点&#xff0c;被广泛应用于 Web 开发、数据科学、人工智能等领域。无论你是初学者还是有一定编程经验的开发者&#xff0c;掌握 Python 的基础知识都是开启编程之旅的第一步。让我们一起来探索 Pyt…

不排斥温暖,不迎合热闹

在纷繁复杂的现代社会&#xff0c;每个人都在寻找自己的生活方式。有人热衷于社交活动&#xff0c;享受热闹的场面&#xff1b;而有人则偏爱宁静&#xff0c;寻求内心的平和。 拥抱温暖&#xff0c;珍视人际关系 温暖往往来源于人与人之间的深厚情感。无论是家庭的温馨、朋友…

Hive SQL-DML-insert插入数据

Hive SQL-DML-insert插入数据 1. 插入静态数据 可以直接插入具体的值到Hive表中&#xff1a; INSERT INTO TABLE tablename (column1, column2, column3) VALUES (value1, value2, value3),(value4, value5, value6),...;2. 插入查询结果 将一条查询的结果直接插入到另一个表中…

数据猎手:使用Java和Apache HttpComponents库下载Facebook图像

引言 在信息驱动的时代&#xff0c;互联网上的数据成为了无可比拟的宝藏。本文旨在探讨如何通过利用Java和Apache HttpComponents库&#xff0c;从全球最大的社交网络平台Facebook上获取图像数据。 作为全球最大的社交网络平台&#xff0c;Facebook聚集了数以亿计的用户&#…

uniapp——点赞、取消点赞

案例 更新点赞状态&#xff0c;而不是每次都刷新整个列表。避免页面闪烁&#xff0c;提升用户体验 代码 <view class"funcBtn zan" click"onZan(index,item.id)"><image src"/static/images/circle/zan.png" mode"aspectFill&…

Python基础学习之知识碎片

字符串可以用 运算符连接在一起&#xff0c;用 * 运算符重复。Python 中的字符串有两种索引方式&#xff0c;从左往右以 0 开始&#xff0c;从右往左以 -1 开始。“Python中的字符串不能改变”强调的是字符串的这一特性&#xff0c;即字符串对象一旦创建&#xff0c;其内容就是…

富文本编辑器CKEditor4简单使用-07(处理浏览器不支持通过工具栏粘贴问题 和 首行缩进的问题)

富文本编辑器CKEditor4简单使用-07&#xff08;处理浏览器不支持通过工具栏粘贴问题 和 首行缩进的问题&#xff09; 1. 前言——CKEditor4快速入门2. 默认情况下的粘贴2.1 先看控制粘贴的3个按钮2.1.1 工具栏粘贴按钮2.1.2 存在的问题 2.2 不解决按钮问题的情况下2.2.1 使用ct…

【QuikGraph】C#调用第三方库实现迪杰斯特拉(Dijkstra)算法功能

QuikGraph库介绍 项目地址&#xff1a;https://github.com/KeRNeLith/QuikGraph QuikGraph为.NET提供了通用的有向/无向图数据结构和算法。 QuikGraph提供了深度优先搜索、广度优先搜索、A*搜索、最短路径、k最短路径&#xff0c;最大流量、最小生成树等算法。 QuikGraph最初…