Java基于Redis实现分布式锁

Java基于Redis实现分布式锁分布式锁可以基于很多种方式实现 比如 zookeeper redis 不管哪种方式 他的基本原理是不变的 用一个状态值表示锁 对锁的占用和释放通过状态值来标识 一 为什么 Redis 可以方便地实现分布式锁 1 Redis 为单进程单线程模式 采用队列模式将并发访问变成串行访问 且多客户端对 Redis 的连接并不存在竞争关系 2 Redis 的 SETNX 命令可以方便的实现分布式锁 setN

分布式锁可以基于很多种方式实现,比如zookeeper、redis…。不管哪种方式,他的基本原理是不变的:用一个状态值表示锁,对锁的占用和释放通过状态值来标识。

一、为什么Redis可以方便地实现分布式锁

1、Redis为单进程单线程模式,采用队列模式将并发访问变成串行访问,且多客户端对Redis的连接并不存在竞争关系。

2、Redis的SETNX命令可以方便的实现分布式锁。

setNX(SET if Not eXists)

语法:SETNX key value

返回值:设置成功,返回 1 ;设置失败,返回 0 。

当且仅当 key 不存在时将 key 的值设为 value,并返回1;若给定的 key 已经存在,则 SETNX 不做任何动作,并返回0。

综上所述,可以通过setnx的返回值来判断是否获取到锁,并且不用担心并发访问的问题,因为Redis是单线程的,所以如果返回1则获取到锁,返回0则没获取到。当业务操作执行完后,一定要释放锁,释放锁的逻辑很简单,就是把之前设置的key删除掉即可,这样下次又可以通过setnx该key获取到锁了。

二、分布式锁实现

我们已经知道可以通过Redis自带的函数setNX来实现分布式锁,具体实现步骤如下。

我在一台CentOS7的linux虚拟机中安装了Redis服务,ip地址为:192.168.246.130,服务端口为:6379。

下面是java通过redis实现分布式锁的例子:

import redis.clients.jedis.Jedis; public class RedisLock { //锁的key private static final String key = "DistributedRedisLock"; private static Integer count = 0; public static void main(String[] args) { for(int i=0;i<1000;i++){ new Thread(new Runnable() { @Override public void run() { //获取Redis连接 Jedis jedis = new Jedis("192.168.246.130", 6379); try{ while(true){ //获取锁 if(jedis.setnx(key, Thread.currentThread().getName()) == 1){ try{ System.out.println("线程("+Thread.currentThread().getName()+")获取到锁,开始执行操作"); count++; System.out.println(count); break; }finally{ System.out.println("操作执行完成,释放锁"); //操作执行完一定要释放锁,所以在finally块中执行 jedis.del(key); } }else{ //返回的不是1,说明已经有某个线程获取到了锁 try { //等待100毫秒之后重试 Thread.sleep(100l); } catch (InterruptedException e) { e.printStackTrace(); } } } }catch(Exception e){ e.printStackTrace(); }finally{ //释放Redis连接 jedis.disconnect(); } } }).start(); } } }

 

上述代码的输出结果为:

线程(Thread-320)获取到锁,开始执行操作

1

操作执行完成,释放锁

线程(Thread-463)获取到锁,开始执行操作

2

操作执行完成,释放锁

线程(Thread-997)获取到锁,开始执行操作

3

操作执行完成,释放锁

...

线程(Thread-409)获取到锁,开始执行操作

998

操作执行完成,释放锁

线程(Thread-742)获取到锁,开始执行操作

999

操作执行完成,释放锁

线程(Thread-286)获取到锁,开始执行操作

1000

操作执行完成,释放锁

上述代码虽然是在单应用多线程情况下测试的,但即便是在分布式环境下多应用多线程去获取锁,结果依然是正确的。

三、解决死锁问题

之前的例子代码只是测试代码,只是为了说明原理,例子本身很简单,所以有一些考虑不周的地方。比如当获取到锁之后在业务操作执行过程中发生了环境问题导致断开了和Redis的连接,那就无法在finally块中释放锁,导致其他等待获取锁的线程无限等待下去,也就是发生了死锁现象。

解决方式:

可以在Redis中给锁设置一个过期时间,这样即便无法释放锁,锁也能在一段时间后自动释放。

代码上只需要在获取到锁之后在try语句块中加入如下代码:

jedis.expire(key, 10); //这里给锁设置10秒的过期时间

更妥善的解决方式:

第一个解决方式并不是很好,因为当业务操作处理时间很长,超过了设置的过期时间,那锁就自动释放了,然后再执行finally块中释放锁的操作时,这个锁可能已经被其他线程所持有,会导致把其他线程持有的锁给释放了,从而导致并发问题。所以更妥善一点的方式是在释放锁时判断一下锁是否已经过期,如果已经过期就不用再释放了。

代码上把获取到锁之后的操作改为如下代码:

long start = System.currentTimeMillis(); //获取起始时间毫秒数 try{ jedis.expire(key, 10); ... }finally{ ... if(System.currentTimeMillis() < start+10*1000){ //如果之前设置的锁还未过期,则释放掉 jedis.del(key); } }

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/201676.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月20日 上午8:52
下一篇 2026年3月20日 上午8:52


相关推荐

  • Attention机制与Self-Attention机制的区别

    Attention机制与Self-Attention机制的区别本文主要讲解 Attention 机制与 Self Attention 机制的区别 默认读者已经了解过 Attention Self Attention Transformer seq2seqmodel 传统的 Attention 机制在一般任务的 Encoder Decodermodel 中 输入 Source 和输出 Target 内容是不一样的 比如对于英 中机器翻译来说 Source 是英文句子 Target 是对应的翻译出的中文句子 Attention 机制发生在 Target 的元素 Query 和

    2026年3月18日
    2
  • Claude Code & 智谱GLM-4.6 环境配置指南 (Windows/macOS/Ubuntu)

    Claude Code & 智谱GLM-4.6 环境配置指南 (Windows/macOS/Ubuntu)

    2026年3月12日
    3
  • DFT之Bist

    DFT之BistDFT 即可测试性设计 DesignforTes DFT 是一种集成电路设计技术 它将一些特殊结构在设计阶段植入电路 以便设计完成后进行测试 电路测试有时并不容易 这是因为电路的许多内部节点信号在外部难以控制和观测 通过添加可测试性设计结构 例如扫描链等 内部信号可以暴露给电路外部 ATE ATE 是 AutomaticTes 的缩写 根据客户的测试要求 图纸及参考方案 采用 MCU PLC PC 基于 VB VC 开发平台 利用 TestStand amp LabVIEW 和

    2026年3月17日
    2
  • CImage的学习

    CImage的学习程序代码下载处 http download csdn net source 2098910 下载处 http hi baidu com wangleitongx blog item 9063b03e5e20 html 备注 这个程序是在 xp 系统 vs2008 下做的 当初测试没出什么问题 昨天 2014 11 11 我下了程序在 win7 下面测试 出现了评

    2025年12月2日
    8
  • pyd文件介绍

    pyd文件介绍pyd 一般是 python 外的其他语言如 C C 编写的 python 扩展模块 即 python 的一个动态链接库 与 dll 文件相当 在 linux 系统中一般为 so 文件 也有的时候 为了对 python 文件进行加密 会把 python 模块编译成 pyd 文件 供其他人使用 拿到一个 pyd 文件 在没有文档说明的情况下 可以试试查看模块内的一些函数和类的用法 首先 importXXX pyd 的文件名 然后直接 print dir XXX print help XXX 其中 dir 列出了属性和方法 help

    2025年8月12日
    4
  • android之onCreateOptionsMenu失效,按菜单键无反应

    做点名app的时候,由于教师端和学生端UI相似,所以用了一套UI框架,结果修改一番之后,点击菜单键无反应,也就是下面的onCreateOptionsMenu不执行了,  @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.main, menu);

    2022年3月11日
    234

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号