返回顶部
首页 > 资讯 > 前端开发 > VUE >Java从零实现Redis分布式锁的方法教程
  • 170
分享到

Java从零实现Redis分布式锁的方法教程

2024-04-02 19:04:59 170人浏览 薄情痞子
摘要

这篇文章主要讲解了“Java从零实现Redis分布式锁的方法教程”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java从零实现Redis分布式锁的方法教程”

这篇文章主要讲解了“Java从零实现Redis分布式的方法教程”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java从零实现Redis分布式锁的方法教程”吧!

为什么需要分布式锁

jdk 中为我们提供了加锁的方式:

(1)synchronized 关键字

(2)volatile + CAS 实现的乐观锁

(3)ReadWriteLock 读写锁

(4)ReenTrantLock 可重入锁

等等,这些锁为我们变成提供极大的便利性,保证在多线程的情况下,保证线程安全

但是在分布式系统中,上面的锁就统统没用了。

我们想要解决分布式系统中的并发问题,就需要引入分布式锁的概念。

java 代码实现

创作动机

首先是对锁实现原理的一个实现,理论指导实践,实践完善理论。

晚上关于 redis 分布式锁的文章一大堆,但是也都稂莠不齐。

redis 分布式锁工具有时候中间件团队不见得会提供,提供了也不见得经常维护,不如自己实现一个,知道原理,也方便修改。

接口定义

为了便于和 JDK 复用,我们让接口继承自 jdk 的 Lock 接口。

package com.GitHub.houbb.lock.api.core;  import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock;   public interface ILock extends Lock {           boolean tryLock(long time, TimeUnit unit,                     String key) throws InterruptedException;           boolean tryLock(String key);           void unlock(String key);  }

方法我们只添加了三个比较常用的核心方法,作为第一个版本,简单点。

后续陆续添加即可。

抽象实现

为了便于后期添加更多的所实现,这里首先实现了一个公用的抽象父类。

package com.github.houbb.lock.redis.core;  import com.github.houbb.lock.api.core.ILock; import com.github.houbb.lock.redis.constant.LockRedisConst; import com.github.houbb.wait.api.IWait;  import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Condition;   public abstract class AbstractLockRedis implements ILock {           private final IWait wait;      protected AbstractLockRedis(IWait wait) {         this.wait = wait;     }      @Override     public void lock() {         throw new UnsupportedOperationException();     }      @Override     public void lockInterruptibly() throws InterruptedException {         throw new UnsupportedOperationException();     }      @Override     public boolean tryLock() {         return tryLock(LockRedisConst.DEFAULT_KEY);     }      @Override     public void unlock() {         unlock(LockRedisConst.DEFAULT_KEY);     }      @Override     public boolean tryLock(long time, TimeUnit unit, String key) throws InterruptedException {         long startTimeMills = System.currentTimeMillis();          // 一次获取,直接成功         boolean result = this.tryLock(key);         if(result) {             return true;         }          // 时间判断         if(time <= 0) {             return false;         }         long durationMills = unit.toMillis(time);         long endMills = startTimeMills + durationMills;          // 循环等待         while (System.currentTimeMillis() < endMills) {             result = tryLock(key);             if(result) {                 return true;             }              // 等待 10ms             wait.wait(TimeUnit.MILLISECONDS, 10);         }         return false;     }      @Override     public synchronized boolean tryLock(long time, TimeUnit unit) throws InterruptedException {         return tryLock(time, unit, LockRedisConst.DEFAULT_KEY);     }      @Override     public Condition newCondition() {         throw new UnsupportedOperationException();     }  }

最核心的实际上是 public boolean tryLock(long time, TimeUnit unit, String key) throws InterruptedException 方法。

这个方法会调用 this.tryLock(key) 获取锁,如果成功,直接返回;如果不成功,则循环等待。

这里设置了超时时间,如果超时,则直接返回 true。

redis 锁实现

我们实现的 redis 分布锁,继承自上面的抽象类。

package com.github.houbb.lock.redis.core;  import com.github.houbb.heaven.util.lang.StringUtil; import com.github.houbb.id.api.Id; import com.github.houbb.id.core.util.IdThreadLocalHelper; import com.github.houbb.lock.redis.constant.LockRedisConst; import com.github.houbb.lock.redis.exception.LockRedisException; import com.github.houbb.lock.redis.support.operator.IOperator; import com.github.houbb.wait.api.IWait;   public class LockRedis extends AbstractLockRedis {           private final IOperator redisOperator;           private final Id id;      public LockRedis(IWait wait, IOperator redisOperator, Id id) {         super(wait);         this.redisOperator = redisOperator;         this.id = id;     }      @Override     public boolean tryLock(String key) {         final String requestId = id.id();         IdThreadLocalHelper.put(requestId);          return redisOperator.lock(key, requestId, LockRedisConst.DEFAULT_EXPIRE_MILLS);     }      @Override     public void unlock(String key) {         final String requestId = IdThreadLocalHelper.get();         if(StringUtil.isEmpty(requestId)) {             String threadName = Thread.currentThread().getName();             throw new LockRedisException("Thread " + threadName +" not contains requestId");         }          boolean unlock = redisOperator.unlock(key, requestId);         if(!unlock) {             throw new LockRedisException("Unlock key " + key + " result is failed!");         }     } }

这里就是 redis 锁的核心实现了,如果不太理解,建议回顾一下原理篇:

redis 分布式锁原理详解

加锁

加锁部分,这里会生成一个 id 标识,用于区分当前操作者。

为了安全也设置了默认的超时时间。

当然这里是为了简化调用者的使用成本,开发在使用的时候只需要关心自己要加锁的 key 即可。

当然,甚至连加锁的 key 都可以进一步抽象掉,比如封装 @DistributedLock 放在方法上,即可实现分布式锁。这个后续有时间可以拓展,原理也不难。

解锁

解锁的时候,就会获取当前进程的持有标识。

凭借当前线程持有的 id 标识,去解锁。

IOperator

我们对 redis 的操作进行了抽象,为什么抽象呢?

因为 redis 服务种类实际很多,可以是 redis 单点,集群,主从,哨兵。

连接的客户端也可以很多,jedis,spring redisTemplate, codis, redisson 等等。

这里为了后期拓展方便,就对操作进行了抽象。

接口

定义接口如下:

package com.github.houbb.lock.redis.support.operator;   public interface IOperator {           boolean lock(String lockKey, String requestId, int expireTimeMills);           boolean unlock(String lockKey, String requestId);  }

jedis 实现

我们实现一个 jedis 单点版本的:

package com.github.houbb.lock.redis.support.operator.impl;  import com.github.houbb.lock.redis.constant.LockRedisConst; import com.github.houbb.lock.redis.support.operator.IOperator; import redis.clients.jedis.Jedis;  import java.util.Collections;   public class JedisOperator implements IOperator {           private final Jedis jedis;      public JedisOperator(Jedis jedis) {         this.jedis = jedis;     }           @Override     public boolean lock(String lockKey, String requestId, int expireTimeMills) {         String result = jedis.set(lockKey, requestId, LockRedisConst.SET_IF_NOT_EXIST, LockRedisConst.SET_WITH_EXPIRE_TIME, expireTimeMills);         return LockRedisConst.LOCK_SUCCESS.equals(result);     }           @Override     public boolean unlock(String lockKey, String requestId) {         String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";         Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));         return LockRedisConst.RELEASE_SUCCESS.equals(result);     }  }

这里时最核心的部分。

别看简单几行代码,需要注意的点还是很多的。

加锁

加锁时附带 requestId,用来标识自己为锁的持有者。

SETNX 当 key 不存在时才进行加锁。

设置加锁的过期时间,避免因异常等原因未释放锁,导致锁的长时间占用。

解锁

使用 lua 脚本,保证操作的原子性。

为了证明为锁的持有者,传入 requestId。

测试验证

maven 引入

<dependency>     <groupId>com.github.houbb</groupId>     <artifactId>lock-core</artifactId>     <version>0.0.1</version> </dependency>

测试代码

Jedis jedis = new Jedis("127.0.0.1", 6379); IOperator operator = new JedisOperator(jedis);  // 获取锁 ILock lock = LockRedisBs.newInstance().operator(operator).lock();  try {     boolean lockResult = lock.tryLock();     System.out.println(lockResult);     // 业务处理 } catch (Exception e) {     e.printStackTrace(); } finally {     lock.unlock(); }

小结

到这里,一个简单版本的 redis 分布式锁就实现完成了。

当然还有很多可以改进的地方:

(1)比如引入递增的 sequence,避免分布式锁中的 GC 导致的问题

(2)对于更多 redis 服务端+客户端的支持

(3)对于注解式 redis 分布式锁的支持

感谢各位的阅读,以上就是“Java从零实现Redis分布式锁的方法教程”的内容了,经过本文的学习后,相信大家对Java从零实现Redis分布式锁的方法教程这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是编程网,小编将为大家推送更多相关知识点的文章,欢迎关注!

--结束END--

本文标题: Java从零实现Redis分布式锁的方法教程

本文链接: https://lsjlt.com/news/84458.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Java从零实现Redis分布式锁的方法教程
    这篇文章主要讲解了“Java从零实现Redis分布式锁的方法教程”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java从零实现Redis分布式锁的方法教程”...
    99+
    2024-04-02
  • redis实现分布式锁的方法
    本篇文章展示了redis实现分布式锁的方法具体操作,代码简明扼要容易理解,绝对能让你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。分布式锁其实可以理解为:控制分布式系统有序的去对共享资源进行操作,通过互...
    99+
    2024-04-02
  • Python+Redis从零打造分布式锁实战示例
    目录引言1. 简单实现(基于SETNX命令)2. 改进:设置超时时间(expire命令)3. 进一步改进:使用Lua脚本保证原子性4. 更完善的实现,Redlock算法总结引言 在分布式系统中,多个节点可能需要访问同一共...
    99+
    2024-01-29
    Python Redis分布式锁 Python Redis
  • redis中分布式锁的实现方法
    小编给大家分享一下redis中分布式锁的实现方法,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!redis分布式锁:1、实现原理利...
    99+
    2024-04-02
  • Java实现redis分布式锁的三种方式
    目录一、引入原因二、分布式锁实现过程中的问题问题一:异常导致锁没有释放问题二:获取锁与设置过期时间操作不是原子性的问题三:锁过期之后被别的线程重新获取与释放问题四:锁的释放不是原子性...
    99+
    2022-11-13
    Java redis分布式锁 Java 分布式锁
  • Redis分布式锁的实现方式
    目录一、分布式锁是什么1、获取锁2、释放锁二、代码实例上面代码存在锁误删问题:三、基于SETNX实现的分布式锁存在下面几个问题1、不可重入2、不可重试3、超时释放4、主从一致性四、Redisson实现分布式锁1、pom2...
    99+
    2023-04-03
    Java Redis分布式锁实现方式 实现Redis分布式锁 Redis分布式锁实现
  • Redis实现分布式锁的方法示例
    之前我们使用的定时任务都是只部署在了单台机器上,为了解决单点的问题,为了保证一个任务,只被一台机器执行,就需要考虑锁的问题,于是就花时间研究了这个问题。到底怎样实现一个分布式锁呢? 锁的本质就是互斥,保证任...
    99+
    2022-06-04
    分布式 示例 方法
  • 使用Redis实现分布式锁的方法
    目录Redis 中的分布式锁如何使用分布式锁的使用场景使用 Redis 来实现分布式锁使用 set key value px milliseconds nx 实现SETNX+Lua 实现使用 Redlock 实现分布式锁...
    99+
    2022-06-16
    Redis分布式锁
  • Redis实现分布式锁方法详细
    目录1. 单机数据一致性2. 分布式数据一致性3. Redis实现分布式锁3.1 方式一3.2 方式二(改进方式一)3.3 方式三(改进方式二)3.4 方式四(改进方式三)3.5 方...
    99+
    2024-04-02
  • Java基于Redis实现分布式锁
    分布式锁可以基于很多种方式实现,比如zookeeper、redis...。不管哪种方式,他的基本原理是不变的:用一个状态值表示锁,对锁的占用和释放通过状态值来标识。一、为什么Redis可以方便地实现分布式锁Redis为单进程单线程模式,采用...
    99+
    2015-09-14
    java教程 Java
  • redis分布式锁的实现
    一、使用分布式锁要满足的几个条件:1、系统是一个分布式系统(关键是分布式,单机的可以使用ReentrantLock或者synchronized代码块来实现)2、共享资源(各个系统访问同一个资源,资源的载体可...
    99+
    2024-04-02
  • Redis——》实现分布式锁
    推荐链接:     总结——》【Java】     总结——》【Mysql】     总结——》【Redis】     总结——》【Kafka】     总结——》【Spring】     总结—...
    99+
    2023-09-03
    redis 分布式 过期 lua
  • Redis实现分布式锁
    单体锁存在的问题 在单体应用中,如果我们对共享数据不进行加锁操作,多线程操作共享数据时会出现数据一致性问题。 (下述实例是一个简单的下单问题:从redis中获取库存,检查库存是否够,>0才允许下单) 我们的解决办法通常是加锁。如下加单体锁...
    99+
    2023-08-16
    分布式 java jvm
  • Redis实现分布式锁的方法是什么
    本篇内容介绍了“Redis实现分布式锁的方法是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!在一个分布...
    99+
    2024-04-02
  • Redis实现分布式锁的方法有哪些
    今天小编给大家分享一下Redis实现分布式锁的方法有哪些的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。1. 单机数据一致性单...
    99+
    2023-07-02
  • Redis分布式锁实现的方法是什么
    本篇内容主要讲解“Redis分布式锁实现的方法是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Redis分布式锁实现的方法是什么”吧!一、分布式锁是什么分布式锁是 满足分布式系统或集群模式下...
    99+
    2023-07-05
  • Redis分布式锁的正确实现方式
    Redis分布式锁的正确实现方式?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。可靠性首先,为了确保分布式锁可用,我们至少要确保...
    99+
    2024-04-02
  • Redis数据库中实现分布式锁的方法
    分布式锁是一个在很多环境中非常有用的原语,它是不同进程互斥操作共享资源的唯一方法。有很多的开发库和博客描述如何使用Redis实现DLM(Distributed Lock Manager),但是每个开发库使用...
    99+
    2022-06-04
    分布式 数据库中 方法
  • Redis实现分布式锁的几种方法总结
    Redis实现分布式锁的几种方法总结 分布式锁是控制分布式系统之间同步访问共享资源的一种方式。在分布式系统中,常常需要协调他们的动作。如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问...
    99+
    2022-06-04
    分布式 几种方法 Redis
  • Redis实现分布式锁的五种方法详解
    目录1. 单机数据一致性2. 分布式数据一致性3. Redis实现分布式锁3.1 方式一3.2 方式二(改进方式一)3.3 方式三(改进方式二)3.4 方式四(改进方式三)3.5 方式五(改进方式四)3.6 小结在单体应...
    99+
    2022-06-14
    Redis 分布式锁
软考高级职称资格查询
推荐阅读
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作