Redisson 分布式锁的使用详解

news/2024/9/20 3:23:21/ 标签: 分布式

一、分布式锁的概述

1.1 分布式锁的背景

在单机系统中,Java 提供了 synchronizedLock 等锁机制来确保并发情况下的线程安全。然而,在分布式系统中,多个服务实例运行在不同的物理或虚拟机上,无法直接使用这些本地的锁机制来控制对共享资源的访问。

为了在分布式环境中控制对共享资源的访问,就需要引入一种能够跨多台服务器实例的锁机制,这就是分布式锁。Redis 作为一种高性能的内存数据库,提供了基于 Redis 的分布式锁实现。Redisson 基于 Redis 对分布式锁进行了封装,提供了简洁易用的 API 来管理分布式锁。

1.2 分布式锁的特性

一个完整的分布式锁需要具备以下几个特性:

  1. 互斥性:同一时刻只能有一个客户端能获得锁,其他客户端必须等待锁被释放后才能继续操作。
  2. 容错性:如果持有锁的客户端因为网络或系统故障而没有主动释放锁,锁应当能够被安全地释放。
  3. 高可用性:锁的请求和释放过程应该是高效的,且在 Redis 节点出现故障时,系统依然能够正常工作。

二、Redisson 分布式锁的原理

Redisson 分布式锁基于 Redis 的 SETNX (set if not exists) 命令实现。基本的原理如下:

  1. 加锁:客户端请求加锁时,会向 Redis 发送一个 SETNX 命令,如果返回值为 1,表示加锁成功。如果返回 0,则说明锁已经被其他客户端持有,当前客户端需要等待。
  2. 自动过期:为了防止客户端因故障而无法释放锁,锁的持有是有过期时间的。通过 Redis 的 EXPIRE 命令,锁在加锁时同时设置过期时间,到期后锁将自动释放。
  3. 解锁:锁持有者执行完任务后,主动向 Redis 发送命令删除锁的 key,从而释放锁,其他等待的客户端才能继续加锁。

Redisson 通过封装 Redis 的这些基础命令,提供了 RLock 接口来方便地实现分布式锁。

三、Redisson 分布式锁的使用

3.1 引入 Redisson 依赖

在项目中使用 Redisson,首先需要在 pom.xml 文件中引入 Redisson 的依赖:

<dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>3.16.3</version>
</dependency>

3.2 Redisson 配置

为了使用 Redisson 分布式锁,首先需要配置 Redisson 客户端。Redisson 支持单节点模式、主从模式、集群模式和哨兵模式等多种 Redis 部署模式。这里我们以单节点模式为例:

import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;public class RedissonConfig {public RedissonClient redissonClient() {Config config = new Config();config.useSingleServer().setAddress("redis://127.0.0.1:6379");return Redisson.create(config);}
}

3.3 使用分布式

在配置好 Redisson 客户端后,可以通过 RedissonClient 来获取 RLock 对象,进行分布式加锁和解锁操作。下面是一个简单的使用示例:

import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;public class DistributedLockExample {private final RedissonClient redissonClient;public DistributedLockExample(RedissonClient redissonClient) {this.redissonClient = redissonClient;}public void executeWithLock() {// 获取锁对象RLock lock = redissonClient.getLock("myLock");try {// 加锁lock.lock();System.out.println("获得锁,执行临界区代码");// 模拟业务逻辑Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();} finally {// 解锁lock.unlock();System.out.println("释放锁");}}
}

在上面的示例中,我们通过 redissonClient.getLock("myLock") 获取一个名为 myLock 的锁对象,并在执行完任务后通过 lock.unlock() 主动释放锁。

3.4 设置锁的超时时间

为了防止因异常情况导致锁无法释放,Redisson 提供了设置锁超时时间的功能。在获取锁时,可以通过 lock.lock(long leaseTime, TimeUnit unit) 方法指定锁的持有时间。例如,下面的代码将设置锁的持有时间为 10 秒:

public void executeWithTimeoutLock() {RLock lock = redissonClient.getLock("myLock");try {// 加锁并设置超时时间为10秒lock.lock(10, TimeUnit.SECONDS);System.out.println("获得锁,执行临界区代码");// 模拟业务逻辑Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();} finally {// 无需主动解锁,锁会在10秒后自动释放if (lock.isHeldByCurrentThread()) {lock.unlock();}System.out.println("释放锁");}
}

四、Redisson 分布式锁的应用场景

4.1 控制并发访问

在电商、抢购等高并发场景中,多个用户同时发起对同一商品的抢购请求,此时需要使用分布式锁来控制对库存资源的并发访问,防止超卖或重复购买。

public void purchase(String productId) {RLock lock = redissonClient.getLock("product:" + productId);try {// 尝试获取锁if (lock.tryLock(5, 10, TimeUnit.SECONDS)) {// 执行购买逻辑System.out.println("购买成功");} else {System.out.println("获取锁失败,购买失败");}} catch (InterruptedException e) {e.printStackTrace();} finally {if (lock.isHeldByCurrentThread()) {lock.unlock();}}
}

4.2 分布式任务调度

分布式系统中,任务调度器往往有多个实例在同时运行。如果多个实例同时执行相同的任务,可能会导致数据重复处理或任务冲突。此时可以通过 Redisson 分布式锁确保同一时刻只有一个实例能够执行任务。

public void scheduleTask() {RLock lock = redissonClient.getLock("taskLock");try {if (lock.tryLock(1, TimeUnit.MINUTES)) {System.out.println("获得锁,执行调度任务");// 执行定时任务}} catch (InterruptedException e) {e.printStackTrace();} finally {if (lock.isHeldByCurrentThread()) {lock.unlock();}}
}

4.3 分布式事务

分布式系统中,为了确保多个数据库或服务之间的数据一致性,可以使用 Redisson 分布式锁来控制对共享资源的访问,从而实现分布式事务的控制。

五、Redisson 分布式锁的优缺点

5.1 优点

  1. 实现简单:Redisson 提供了简洁的 API,开发者可以轻松地实现分布式锁功能。
  2. 丰富的分布式工具:除了分布式锁,Redisson 还提供了其他分布式工具,如分布式集合、队列、布隆过滤器等,适用于多种场景。
  3. 自动续期:Redisson 提供了自动续期功能,防止因任务执行时间过长导致锁意外释放。

5.2 缺点

  1. 依赖 Redis:Redisson 是基于 Redis 实现的分布式锁,依赖于 Redis 的可用性和性能。
  2. **锁的粒度

问题**:在使用分布式锁时,需要合理设计锁的粒度。锁粒度过大会导致性能瓶颈,锁粒度过小则可能导致竞争加剧。

六、总结

Redisson 作为 Redis 的高级客户端,提供了简单易用的分布式锁实现,能够很好地解决分布式系统中的并发控制问题。通过 Redisson,开发者可以快速实现分布式锁,并应用到电商、任务调度、分布式事务等场景中。

在使用 Redisson 分布式锁时,除了基本的加锁和解锁操作外,还需要合理设计锁的粒度,确保锁的可用性和系统性能的平衡。


http://www.ppmy.cn/news/1527866.html

相关文章

Activiti7《第二式:破剑式》——工作流中的以柔克刚

冲冲冲&#xff01;开干 这篇文章将分为九个篇章&#xff0c;带你逐步掌握工作流的核心知识。这篇文章将带你深入探讨工作流中的 “破剑式”&#xff0c;揭示如何通过 柔与刚 的结合来破解工作流的复杂性。本篇包含了 Activiti7 环境的进一步优化和表结构的深入分析&#xff0…

【读书笔记-《30天自制操作系统》-22】Day23

本篇内容比较简单&#xff0c;集中于显示问题。首先编写了应用程序使用的api_malloc&#xff0c;然后实现了在窗口中画点与画线的API与应用程序。有了窗口显示&#xff0c;还要实现关闭窗口的功能&#xff0c;于是在键盘输入API的基础上实现了按下按键关闭窗口。最后发现用上文…

O1-preview:智能预测与预取驱动的性能优化处理器设计OPEN AI

# 创作不易&#xff0c;您的打赏、关注、点赞、收藏和转发是我坚持下去的动力&#xff01; O1-preview 是一种用于性能优化的处理器设计原理&#xff0c;主要通过智能预测和数据预取来提升处理器的执行效率。以下是对 O1-preview 原理的详细介绍&#xff0c;以及它相对于以往的…

时空大数据平台:激活新质生产力的智慧引擎

在数字化转型的浪潮中&#xff0c;时空大数据平台以其独特的价值&#xff0c;成为推动新质生产力发展的关键力量。本文不仅深入剖析时空大数据平台的定义与内涵&#xff0c;探讨其在智慧城市、智慧农业、环境管理、应急管理等领域的应用成效&#xff0c;还将详尽阐述平台如何通…

海鲜市场|基于springboot的网络海鲜市场系设计与实现(附项目源码+论文+数据库)

私信或留言即免费送开题报告和任务书&#xff08;可指定任意题目&#xff09; 目录 一、摘要 二、相关技术 三、系统设计 四、数据库设计 五、核心代码 六、论文参考 七、源码获取 一、摘要 计算机网络发展到现在已经好几十年了&#xff0c;在理论上面已…

ceph clients failing to respond to cache pressure

问题描述 prometheus 告警 🚨 触发中告警 [1] MDS_CLIENT_RECALL告警详请 🚨 触发中告警 [1] ⁣告警名称 : RookCephHealthWarn告警级别 : WARNING告警实例 : MDS_CLIENT_RECALL 告警状态 : 🚨 FIRING开始时间 : 2024-09

清理C盘缓存,如何针对Windows10系统,专业地调整和优化C盘缓存设置

在Windows10系统中&#xff0c;合理地管理C盘&#xff08;通常是系统盘&#xff09;的缓存设置&#xff0c;对于保持系统性能、提升响应速度以及避免磁盘空间不足等问题至关重要。缓存主要涉及到系统文件、临时文件、应用程序缓存等多个方面。下面将详细介绍如何针对Windows10系…

HarmonyOS开发实战( Beta5.0)蓝牙实现服务端和客户端通讯详解

鸿蒙HarmonyOS开发往期必看&#xff1a; HarmonyOS NEXT应用开发性能实践总结 最新版&#xff01;“非常详细的” 鸿蒙HarmonyOS Next应用开发学习路线&#xff01;&#xff08;从零基础入门到精通&#xff09; 介绍 本示例分为服务端和客户端两个功能模块。 服务端创建蓝牙…

F12抓包08:查看网站Cookie

课程大纲 1、查看Cookie 1. 应用界面查看&#xff1a;按F12进入浏览器的开发者模式 - “应用”&#xff08;Application&#xff09; - Cookie&#xff0c;可查看Cookie并进行增、删、改、查操作。 2. 控制台命令行查看&#xff1a;按F12进入浏览器的开发者模式 - “控制台”&…

Spring-bean的生命周期-尾篇

上回说到阶段9&#xff0c;现在我们接着往下说 阶段10&#xff1a;所有单例bean初始化完成后阶段 所有单例bean实例化完成之后&#xff0c;spring会回调下面这个接口&#xff1a; package org.springframework.beans.factory;public interface SmartInitializingSingleton {…

150+个流行的Instagram标签(及如何找到并正确使用它们)

早在2007年8月&#xff0c;当你还在收音机里唱着“Umbrella”&#xff08;ella…ella&#xff09;的时候&#xff0c;一位名叫Chris Messina的产品设计师向Twitter提出了“使用#&#xff08;井号&#xff09;来分组”的想法。 Twitter的回应是什么&#xff1f;太书呆子气&#…

Cassandra 和 ScyllaDB

Cassandra 和 ScyllaDB 详解 Cassandra 和 ScyllaDB 是现代分布式数据库系统中非常受欢迎的两个选择&#xff0c;它们在性能、可扩展性和高可用性方面有着显著优势&#xff0c;适合大规模、高吞吐量的应用场景。这两者都是面向列的分布式数据库&#xff08;Columnar Store&…

详解TCP的三次握手

TCP&#xff08;三次握手&#xff09;是指在建立一个可靠的传输控制协议 (TCP) 连接时&#xff0c;客户端和服务器之间的三步交互过程。这个过程的主要目的是确保连接是可靠的、双方的发送与接收能力是正常的&#xff0c;并且可以开始数据传输。下面是对每个步骤的详细解释&…

C++ | Leetcode C++题解之第406题根据身高重建队列

题目&#xff1a; 题解&#xff1a; class Solution { public:vector<vector<int>> reconstructQueue(vector<vector<int>>& people) {sort(people.begin(), people.end(), [](const vector<int>& u, const vector<int>& v) …

VirtualBox增加磁盘并给docker用

在VirtualBox新增磁盘 在虚拟机停止的情况下依次选择&#xff0c;然后创建新磁盘 虚拟机新磁盘创建分区、格式化、挂载分区 开机自动挂载新磁盘分区/dev/sdb1&#xff1a; nano /etc/fstab末尾添加一行&#xff1a; /dev/sdb1 /disk02 e…

深入理解ConcurrentHashMap

HashMap为什么线程不安全 put的不安全 由于多线程对HashMap进行put操作&#xff0c;调用了HashMap的putVal()&#xff0c;具体原因&#xff1a; 假设两个线程A、B都在进行put操作&#xff0c;并且hash函数计算出的插入下标是相同的&#xff1b; 当线程A执行完第六行由于时间片…

linux-Linux 内核与模块管理-内核基础

Linux 内核是操作系统的核心&#xff0c;它负责管理硬件资源和提供系统调用接口供用户程序使用。Linux 内核的设计极为灵活和模块化&#xff0c;它允许开发者通过加载和卸载模块来动态地扩展内核的功能。 一、Linux 内核概述 1.1 内核的基本功能 Linux 内核的主要功能可以分…

Python基础语法(3)下

列表和元组 列表是什么&#xff0c;元组是什么 编程中&#xff0c;经常需要使用变量&#xff0c;来保存/表示数据。变量就是内存空间&#xff0c;用来表示或者存储数据。 如果代码中需要表示的数据个数比较少&#xff0c;我们直接创建多个变量即可。 num1 10 num2 20 num3…

【计算机网络】数据链路层深度解析

概述三个重要问题封装成帧差错检测可靠传输 使用广播信道的数据链路层数据链路层的互连设备 媒体接入MAC地址集线器与交换机区别以太网交换机生成树协议STP 概述 链路就是从一个结点到相邻结点的一段物理线路&#xff0c;而中间没有任何其他的交换结点。数据链路是指把实现通信…

数据结构-3.3.栈的链式存储实现

一.链栈的定义&#xff1a; 二.总结&#xff1a;