1. /**
  2. *在redis上实现分布式锁
  3. */
  4. class RedisLock {
  5. private $redisString;
  6. private $lockedNames = [];
  7. public function __construct($param = NULL) {
  8. $this->redisString = RedisFactory::get($param)->string;
  9. }
  10. /**
  11. * 加锁
  12. * @param [type] $name 锁的标识名
  13. * @param integer $timeout 循环获取锁的等待超时时间,在此时间内会一直尝试获取锁直到超时,为0表示失败后直接返回不等待
  14. * @param integer $expire 当前锁的最大生存时间(秒),必须大于0,如果超过生存时间锁仍未被释放,则系统会自动强制释放
  15. * @param integer $waitIntervalUs 获取锁失败后挂起再试的时间间隔(微秒)
  16. * @return [type] [description]
  17. */
  18. public function lock($name, $timeout = , $expire = , $waitIntervalUs = ) {
  19. if ($name == null) return false;
  20. //取得当前时间
  21. $now = time();
  22. //获取锁失败时的等待超时时刻
  23. $timeoutAt = $now + $timeout;
  24. //锁的最大生存时刻
  25. $expireAt = $now + $expire;
  26. $redisKey = "Lock:{$name}";
  27. while (true) {
  28. //将rediskey的最大生存时刻存到redis里,过了这个时刻该锁会被自动释放
  29. $result = $this->redisString->setnx($redisKey, $expireAt);
  30. if ($result != false) {
  31. //设置key的失效时间
  32. $this->redisString->expire($redisKey, $expireAt);
  33. //将锁标志放到lockedNames数组里
  34. $this->lockedNames[$name] = $expireAt;
  35. return true;
  36. }
  37. //以秒为单位,返回给定key的剩余生存时间
  38. $ttl = $this->redisString->ttl($redisKey);
  39. //ttl小于0 表示key上没有设置生存时间(key是不会不存在的,因为前面setnx会自动创建)
  40. //如果出现这种状况,那就是进程的某个实例setnx成功后 crash 导致紧跟着的expire没有被调用
  41. //这时可以直接设置expire并把锁纳为己用
  42. if ($ttl < ) {
  43. $this->redisString->set($redisKey, $expireAt);
  44. $this->lockedNames[$name] = $expireAt;
  45. return true;
  46. }
  47. /*****循环请求锁部分*****/
  48. //如果没设置锁失败的等待时间 或者 已超过最大等待时间了,那就退出
  49. if ($timeout <= || $timeoutAt < microtime(true)) break;
  50. //隔 $waitIntervalUs 后继续 请求
  51. usleep($waitIntervalUs);
  52. }
  53. return false;
  54. }
  55. /**
  56. * 解锁
  57. * @param [type] $name [description]
  58. * @return [type] [description]
  59. */
  60. public function unlock($name) {
  61. //先判断是否存在此锁
  62. if ($this->isLocking($name)) {
  63. //删除锁
  64. if ($this->redisString->deleteKey("Lock:$name")) {
  65. //清掉lockedNames里的锁标志
  66. unset($this->lockedNames[$name]);
  67. return true;
  68. }
  69. }
  70. return false;
  71. }
  72. /**
  73. * 释放当前所有获得的锁
  74. * @return [type] [description]
  75. */
  76. public function unlockAll() {
  77. //此标志是用来标志是否释放所有锁成功
  78. $allSuccess = true;
  79. foreach ($this->lockedNames as $name => $expireAt) {
  80. if (false === $this->unlock($name)) {
  81. $allSuccess = false;
  82. }
  83. }
  84. return $allSuccess;
  85. }
  86. /**
  87. * 给当前所增加指定生存时间,必须大于0
  88. * @param [type] $name [description]
  89. * @return [type] [description]
  90. */
  91. public function expire($name, $expire) {
  92. //先判断是否存在该锁
  93. if ($this->isLocking($name)) {
  94. //所指定的生存时间必须大于0
  95. $expire = max($expire, );
  96. //增加锁生存时间
  97. if ($this->redisString->expire("Lock:$name", $expire)) {
  98. return true;
  99. }
  100. }
  101. return false;
  102. }
  103. /**
  104. * 判断当前是否拥有指定名字的所
  105. * @param [type] $name [description]
  106. * @return boolean [description]
  107. */
  108. public function isLocking($name) {
  109. //先看lonkedName[$name]是否存在该锁标志名
  110. if (isset($this->lockedNames[$name])) {
  111. //从redis返回该锁的生存时间
  112. return (string)$this->lockedNames[$name] = (string)$this->redisString->get("Lock:$name");
  113. }
  114. return false;
  115. }
  116. }

在redis上实现分布式锁的更多相关文章

  1. 使用redis构建可靠分布式锁

    关于分布式锁的概念,具体实现方式,直接参阅下面两个帖子,这里就不多介绍了. 分布式锁的多种实现方式 分布式锁总结 对于分布式锁的几种实现方式的优劣,这里再列举下 1. 数据库实现方式 优点:易理解 缺 ...

  2. 一个Redis实现的分布式锁

    import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.data.redis.conne ...

  3. 基于Redis的简单分布式锁的原理

    参考资料:https://redis.io/commands/setnx 加锁是为了解决多线程的资源共享问题.Java中,单机环境的锁可以用synchronized和Lock,其他语言也都应该有自己的 ...

  4. redis客户端、分布式锁及数据一致性

    Redis Java客户端有很多的开源产品比如Redission.Jedis.lettuce等. Jedis是Redis的Java实现的客户端,其API提供了比较全面的Redis命令的支持:Redis ...

  5. Redis系列(二)--分布式锁、分布式ID简单实现及思路

    分布式锁: Redis可以实现分布式锁,只是讨论Redis的实现思路,而真的实现分布式锁,Zookeeper更加可靠 为什么使用分布式锁: 单机环境下只存在多线程,通过同步操作就可以实现对并发环境的安 ...

  6. 如何用redis正确实现分布式锁?

    先把结论抛出来:redis无法正确实现分布式锁!即使是redis单节点也不行!redis的所谓分布式锁无法用在对锁要求严格的场景下,比如:同一个时间点只能有一个客户端获取锁. 首先来看下单节点下一般r ...

  7. redis系列:分布式锁

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

  8. Redis如何实现分布式锁

    今天我们来聊一聊分布式锁的那些事. 相信大家对锁已经不陌生了,我们在多线程环境中,如果需要对同一个资源进行操作,为了避免数据不一致,我们需要在操作共享资源之前进行加锁操作.在计算机科学中,锁(lock ...

  9. Redis高并发分布式锁详解

    为什么需要分布式锁 1.为了解决Java共享内存模型带来的线程安全问题,我们可以通过加锁来保证资源访问的单一,如JVM内置锁synchronized,类级别的锁ReentrantLock. 2.但是随 ...

随机推荐

  1. scp文件拷贝简易使用

    scp远程复制 属性变化 需要复制所属关系需要用-p选项 源目录复制之后目的目录的属性: srcdrwxr-xr-x. 2 root root 6 9月 4 16:28 2.txt dstdrwxr- ...

  2. 04.UTXO:未使用的交易输出,比特币核心概念之一

    在比特币系统上其实并不存在“账户”,而只有“地址”.只要你愿意,你就可以在比特币区块链上开设无限多个钱包地址,你拥有的比特币数量是你所有的钱包地址中比特币的总和.比特币系统并不会帮你把这些地址汇总起来 ...

  3. JS高阶---函数

    [问题] [主体] 1.什么是函数? ①实现特定功能 ②多条语句的封装体 ③可以重复执行的代码块 2.为什么用函数? 提高代码的复用性,提升效率 3.如何定义函数? ①函数声明定义 ②函数表达式定义③ ...

  4. 201777010217-金云馨《面向对象程序设计Java》第四周总结学习

    2019面向对象程序设计(Java)第4周学习指导及要求 项目 内容 这个作业属于哪个课程 <任课教师博客主页链接>https://www.cnblogs.com/nwnu-daizh/ ...

  5. android 开发工具 adb

    1.abd基本使用 1.启动一个adb应用程序 adb -P <port> start-server # -P指定端口 默认是5037 1.停止adb adb kill-server 2. ...

  6. python27期尚哥讲TFTP:

    TFTP介绍 :TFTP(Trivial File Transfer Protocol,简单⽂件传输协议)是TCP/IP协议簇中的⼀个⽤来在客户端与服务器之间进⾏简单⽂件传输的协议使用tftp这个协议 ...

  7. USACO Buying Hay

    洛谷 P2918 [USACO08NOV]买干草Buying Hay https://www.luogu.org/problem/P2918 JDOJ 2592: USACO 2008 Nov Sil ...

  8. 牛客CSP-S提高组赛前集训营1———2019.10.29 18:30 至 22:00

    期望得分:100+0+10 实际得分:40+0+0 考炸了... T1:题目链接 究竟为什么会这样,,, 仔细研读我的丑代码 发现... 枯辽.... #include<cstdio> # ...

  9. [LeetCode] 905. Sort Array By Parity 按奇偶排序数组

    Given an array A of non-negative integers, return an array consisting of all the even elements of A, ...

  10. [LeetCode] 465. Optimal Account Balancing 最优账户平衡

    A group of friends went on holiday and sometimes lent each other money. For example, Alice paid for ...