1.setnx
锁在redis中最简单的数据结构就是string。最早的时候,上锁的操作一般使用setnx,这个命令是当:lock不存在的时候set一个val,或许你还会记得使用expire来增加锁的过期,解锁操作就是使用del命令,伪代码如下:
if (Redis::setnx("my:lock", 1)) {
  Redis::expire("my:lock", 10);
  // ... do something

  Redis::del("my:lock")
}
这里其实是有问题的,问题就在于setnx和expire中间如果遇到crash等行为,可能这个lock就不会被释放了。

2.set
现在官方建议直接使用set来实现锁。我们可以使用set命令来替代setnx,就是下面这个样子
if (Redis::set("my:lock", 1, "nx", "ex", 10)) {
  ... do something

  Redis::del("my:lock")
}
上面的代码把my:lock设置为1,当且仅当这个lock不存在的时候,设置完成之后设置过期时间为10。
获取锁的机制是对了,但是删除锁的机制直接使用del是不对的。因为有可能导致误删别人的锁的情况。比如,这个锁我上了10s,但是我处理的时间比10s更长,到了10s,这个锁自动过期了,被别人取走了,并且对它重新上锁了。那么这个时候,我再调用Redis::del就是删除别人建立的锁了。
官方对解锁的命令也有建议,建议使用lua脚本,先进行get,再进行del

主控:
$token = rand(1, 100000);

function lock() {
  return Redis::set("my:lock", $token, "nx", "ex", 10);
}

function unlock() {
  $script = `
  if redis.call("get",KEYS[1]) == ARGV[1]
  then
    return redis.call("del",KEYS[1])
  else
    return 0
  end 
  `
  return Redis::eval($script, "my:lock", $token)
}

if (lock()) {
  // do something

  unlock();
}

redis工具类:

public class RedisTool {private static final String LOCK_SUCCESS = "OK";private static final String SET_IF_NOT_EXIST = "NX";private static final String SET_WITH_EXPIRE_TIME = "PX";private static final Long RELEASE_SUCCESS = 1L;/*** 尝试获取分布式锁* @param jedis Redis客户端* @param lockKey 锁* @param requestId 请求标识* @param expireTime 超期时间* @return 是否获取成功*/public static boolean tryGetDistributedLock(Jedis jedis, String lockKey, String requestId, int expireTime) {String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);if (LOCK_SUCCESS.equals(result)) {return true;}return false;}/*** 释放分布式锁* @param jedis Redis客户端* @param lockKey 锁* @param requestId 请求标识* @return 是否释放成功*/public static boolean releaseDistributedLock(Jedis jedis, 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));if (RELEASE_SUCCESS.equals(result)) {return true;}return false;}}

其他:lua脚本的原子性:
Redis 使用单个 Lua 解释器去运行所有脚本,并且, Redis 也保证脚本会以原子性(atomic)的方式执行:当某个脚本正在运行的时候,不会有其他脚本或 Redis 命令被执行。这和使用 MULTI / EXEC 包围的事务很类似。在其他别的客户端看来,脚本的效果(effect)要么是不可见的(not visible),要么就是已完成的(already completed)。另一方面,这也意味着,执行一个运行缓慢的脚本并不是一个好主意。写一个跑得很快很顺溜的脚本并不难,因为脚本的运行开销(overhead)非常少,但是当你不得不使用一些跑得比较慢的脚本时,请小心,因为当这些蜗牛脚本在慢吞吞地运行的时候,其他客户端会因为服务器正忙而无法执行命令。

转载于:https://www.cnblogs.com/tinyj/p/10023615.html

使用Redis实现分布式锁相关推荐

  1. 基于 Redis 实现分布式锁思考

    以下文章来源方志朋的博客,回复"666"获面试宝典 来源:blog.csdn.net/xuan_lu/article/details/111600302 分布式锁 基于redis实 ...

  2. Redis实现分布式锁的深入探究

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 一.分布式锁简介 锁 是一种用来解决多个执行线程 访问共享资源 错 ...

  3. nx set 怎么实现的原子性_基于Redis的分布式锁实现

    前言 本篇文章主要介绍基于Redis的分布式锁实现到底是怎么一回事,其中参考了许多大佬写的文章,算是对分布式锁做一个总结 分布式锁概览 在多线程的环境下,为了保证一个代码块在同一时间只能由一个线程访问 ...

  4. Zookeeper和Redis实现分布式锁,附我的可靠性分析

    作者:今天你敲代码了吗 链接:https://www.jianshu.com/p/b6953745e341 在分布式系统中,为保证同一时间只有一个客户端可以对共享资源进行操作,需要对共享资源加锁来实现 ...

  5. Redis——由分布式锁造成的重大事故

    作者:浪漫先生 原文:juejin.im/post/6854573212831842311 前言 基于Redis使用分布式锁在当今已经不是什么新鲜事了.本篇文章主要是基于我们实际项目中因为redis分 ...

  6. 基于Redis的分布式锁和Redlock算法

    来自:后端技术指南针 1 前言 今天开始来和大家一起学习一下Redis实际应用篇,会写几个Redis的常见应用. 在我看来Redis最为典型的应用就是作为分布式缓存系统,其他的一些应用本质上并不是杀手 ...

  7. 《Redis官方文档》用Redis构建分布式锁

    <Redis官方文档>用Redis构建分布式锁 用Redis构建分布式锁 在不同进程需要互斥地访问共享资源时,分布式锁是一种非常有用的技术手段. 有很多三方库和文章描述如何用Redis实现 ...

  8. 《Redis官方文档》用Redis构建分布式锁(悲观锁)

    2019独角兽企业重金招聘Python工程师标准>>> **用Redis构建分布式锁 ** 在不同进程需要互斥地访问共享资源时,分布式锁是一种非常有用的技术手段. 有很多三方库和文章 ...

  9. redis 实现分布式锁

    为什么80%的码农都做不了架构师?>>>    redis 实现分布式锁 伪代码 lock(){if(jedis.setNx("key",timestamp)){ ...

  10. redis系列:基于redis的分布式锁

    一.介绍 这篇博文讲介绍如何一步步构建一个基于Redis的分布式锁.会从最原始的版本开始,然后根据问题进行调整,最后完成一个较为合理的分布式锁. 本篇文章会将分布式锁的实现分为两部分,一个是单机环境, ...

最新文章

  1. 雪崩 计算机组成原理,计算机组成原理复习资料(学习课件整理版可自学使用).doc...
  2. mac打开class文件
  3. 【UE灯光•简介】UE4光照类型和灯光参数
  4. MPI Maelstrom——Dijkstra
  5. 盖茨庆祝万维网诞生30周年 庆幸自己有机会影响数字革命
  6. MySQL实现SQL Server排名函数
  7. linux下绘图工具dia,功能强劲直逼visio - 潜入技术的海洋 - 51CTO技术博客
  8. SQL--“索引超出了数组界限”
  9. 如何查看oracle客户端的版本,如何查看Oracle客户端版本
  10. keepass和坚果云实现全平台密码管理
  11. 两台(或多台)电脑怎么实现文件共享
  12. 股票交易手续费怎么计算
  13. 河南财经政法大学计算机基础,河南财经政法大学就“忘开必修课”情况说明
  14. Processing入门简介
  15. 《西部世界》与《头号玩家》:哪个才是人类与人工智能相处的正确方式?
  16. SHAMANIC Heil Amazonas-DschungelSHAMA
  17. 风控ML[15] | 风控模型报告以及上线后需要监控的内容
  18. h5聊天页面 jquery_h5聊天室web端(仿微博、微信)|h5仿微信网页端|仿微信界面弹窗...
  19. JAVA验证 手机、邮箱、电话、QQ 格式是否正确
  20. Python电影爬虫,用Excel存储并进行数据可视化分析

热门文章

  1. 计算 JS 数组中最大最小值
  2. Java使用Jolt连接Tuxedo服务器
  3. Android中文API (60) —— DatePicker.OnDateChangedListener
  4. Ubuntu Linux配置IP地址
  5. sink xxx does not exist
  6. 诡异的select *语句报错事件
  7. best single model of RSNA
  8. 3分钟搞懂LSI原理
  9. mysql数据库replace写入_MySQL数据库replace into 用法(insert into 的增强版)
  10. 正态分布的前世今生(一)