千家信息网

Redis Template实现分布式锁

发表于:2025-01-28 作者:千家信息网编辑
千家信息网最后更新 2025年01月28日,今天就跟大家聊聊有关Redis Template实现分布式锁,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。可靠性首先,为了确保分布式锁可用,我
千家信息网最后更新 2025年01月28日Redis Template实现分布式锁

今天就跟大家聊聊有关Redis Template实现分布式锁,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。

可靠性

首先,为了确保分布式锁可用,我们至少要确保锁的实现同时满足以下四个条件:
1.互斥性。在任意时刻,只有一个客户端能持有锁。
2.不会发生死锁。即使有一个客户端在持有锁的期间崩溃而没有主动解锁,也能保证后续其他客户端能加锁。
3.具有容错性。只要大部分的Redis节点正常运行,客户端就可以加锁和解锁。
4.解铃还须系铃人。加锁和解锁必须是同一个客户端,客户端自己不能把别人加的锁给解了。

使用Redis的SETNX命令获取分布式锁的步骤:

•C1和C2线程同时检查时间戳获取锁,执行SETNX命令并都返回0,此时锁仍被C3持有,并且C3已经崩溃
•C1 DEL锁
•C1 使用SETNX命令获取锁,并且成功
•C2 DEL锁
•C2 使用SETNX命令获取锁,并且成功
•ERROR : 由于竞态条件,C1和C2都获取到了锁

幸运的是,以下面的步骤完全可以避免这种情况发生,看看C4线程如何操作

•C4使用SETNX命令获取锁
•C3已经崩溃但是仍然持有锁,所以Redis返回0给C4
•C4使用GET命令获取锁并检查锁是否已经过期,如果没有过期,则继续等待一段时间并重新重试
•如果锁已经过期,C4尝试 GETSET lock.foo
•利用GETSET语法,C4可以检查旧时间是否仍然是过期时间,如果是,则获取锁
•如果另一个客户端C5率先获取到锁,C4执行GETSET命令后将返回非过期时间,然后C4继续从头开始重新尝试获取锁。此操作C4将延长一点C5获取到的锁的过期时间,不过这不是什么大问题。

接下来我们用代码的形式展现:

package com.shuige.components.cache.redis;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.data.redis.core.RedisCallback;import org.springframework.data.redis.core.RedisTemplate;import org.springframework.data.redis.core.ValueOperations;import org.springframework.stereotype.Component;import java.util.Objects;import java.util.concurrent.TimeUnit;/** * Description: 通用Redis帮助类 * User: zhouzhou * Date: 2018-09-05 * Time: 15:39 */@Componentpublic class CommonRedisHelper {  public static final String LOCK_PREFIX = "redis_lock";  public static final int LOCK_EXPIRE = 300; // ms  @Autowired  RedisTemplate redisTemplate;  /**   * 最终加强分布式锁   *   * @param key key值   * @return 是否获取到   */  public boolean lock(String key){    String lock = LOCK_PREFIX + key;    // 利用lambda表达式    return (Boolean) redisTemplate.execute((RedisCallback) connection -> {      long expireAt = System.currentTimeMillis() + LOCK_EXPIRE + 1;      Boolean acquire = connection.setNX(lock.getBytes(), String.valueOf(expireAt).getBytes());      if (acquire) {        return true;      } else {        byte[] value = connection.get(lock.getBytes());        if (Objects.nonNull(value) && value.length > 0) {          long expireTime = Long.parseLong(new String(value));          if (expireTime < System.currentTimeMillis()) {            // 如果锁已经过期            byte[] oldValue = connection.getSet(lock.getBytes(), String.valueOf(System.currentTimeMillis() + LOCK_EXPIRE + 1).getBytes());            // 防止死锁            return Long.parseLong(new String(oldValue)) < System.currentTimeMillis();          }        }      }      return false;    });  }  /**   * 删除锁   *   * @param key   */  public void delete(String key) {    redisTemplate.delete(key);  }}

如何使用呢,导入工具类后:

boolean lock = redisHelper.lock(key);    if (lock) {      // 执行逻辑操作      redisHelper.delete(key);    } else {      // 设置失败次数计数器, 当到达5次时, 返回失败      int failCount = 1;      while(failCount <= 5){        // 等待100ms重试        try {          Thread.sleep(100l);        } catch (InterruptedException e) {          e.printStackTrace();        }        if (redisHelper.lock(key)){          // 执行逻辑操作          redisHelper.delete(key);        }else{          failCount ++;        }      }      throw new RuntimeException("现在创建的人太多了, 请稍等再试");    }

看完上述内容,你们对Redis Template实现分布式锁有进一步的了解吗?如果还想了解更多知识或者相关内容,请关注行业资讯频道,感谢大家的支持。

命令 客户 客户端 时间 分布式 内容 检查 成功 同时 条件 步骤 线程 逻辑 死锁 和解 尝试 主动 幸运 解铃还须系铃人 接下来 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 服务器的计划管理软件 学软件开发 daxue 数据库吸客力度 英雄联盟手游为什么服务器维护 陕西网络营销软件开发定制哪家好 跑跑手游国际服登录服务器超时 闵行区app软件开发系统 软件开发 电商网站代码 网络安全隐私教程 php列表随机三个数据库 山西浪潮服务器虚拟化价格 近4年网络安全事件 2019检验信息网络技术 我的世界服务器压测 网络安全手抄报 动漫 在线传送的文件也经过腾讯服务器 计算机四级网络技术2018 联想服务器如何查询阵列卡 安卓pos机怎么数据库 编程系统和数据库哪个好用 服务器数据恢复方法 欧普康视软件开发怎样 办公室物品管理系统数据库设计 西瓜视频的服务器在哪 国家网络安全应急成员单位 小喇叭广播剧软件开发 数据库2008安装教程6 网络安全保护知识竞赛答案 access数据库二级 sql数据库改变数据类型
0