经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 数据库/运维 » Redis » 查看文章
Redis SETNX实现分布式锁
来源:cnblogs  作者:Rohmeng  时间:2019/8/23 8:41:54  对本文有异议

1、某进程1执行 SETNX lock 以尝试获取锁

2、由于某进程2已获得了锁,所以进程1执行 SETNX lock 返回0,即获取锁失败

3、进程1执行 GET lock 来检测锁是否已超时,如果没超时,则线程等待一段时间,再次检测

4、如果进程1检测到锁已超时,即当前的时间大于键 lock 的值,进程1会执行以下操作

GETSET lock <current Unix timestamp + lock timeout + 1>

5、由于 GETSET 操作在设置键的值的同时,还会返回键的旧值,通过比较键 lock 的旧值是否小于当前时间,可以判断进程是否已获得锁

6、假如另一个进程3也检测到锁已超时,并在进程1之前执行了 GETSET 操作,那么进程1的 GETSET 操作返回的是一个大于当前时间的时间戳,这样进程1就不会获得锁而继续等待。注意到,即使进程1接下来将键 lock 的值设置了比进程3设置的更大的值也没影响。

另外,值得注意的是,在进程释放锁,即执行 DEL lock 操作前,需要先判断锁是否已超时。如果锁已超时,那么锁可能已由其他进程获得,这时直接执行 DEL lock 操作会导致把其他进程已获得的锁释放掉。

C# Code

  1. using System;
  2. using System.Threading;
  3. using System.Threading.Tasks;
  4. using CSRedis;
  5. namespace RedisLockDemo
  6. {
  7. public class CsRedisLock
  8. {
  9. private static readonly int _lock_timeout = 40;
  10. private static readonly string _lock_key = "lock";
  11. public static void Test()
  12. {
  13. var rds = new CSRedisClient("127.0.0.1:6379,password=123456,defaultDatabase=13,poolsize=50,ssl=false");
  14. RedisHelper.Initialization(rds);
  15. Parallel.For(0, 13, x =>
  16. {
  17. if (GetLock(_lock_key))
  18. {
  19. Console.WriteLine($"person:{x},线程ID:{Thread.CurrentThread.ManagedThreadId},获得锁 woking");
  20. if (DateTimeOffset.Now.ToUnixTimeMilliseconds() < RedisHelper.Get<long>(_lock_key))
  21. {
  22. //释放锁
  23. RedisHelper.Del(_lock_key);
  24. }
  25. }
  26. else
  27. {
  28. Console.WriteLine($"person:{x},线程ID:{Thread.CurrentThread.ManagedThreadId},获取锁异常");
  29. }
  30. });
  31. Console.WriteLine();
  32. }
  33. private static bool GetLock(string key)
  34. {
  35. bool getLocked = false;
  36. try
  37. {
  38. while (!getLocked)
  39. {
  40. var now = DateTimeOffset.Now.ToUnixTimeMilliseconds();
  41. var lock_time = now + _lock_timeout + 1;
  42. getLocked = RedisHelper.SetNx(key, lock_time);
  43. //判断是否获取锁,
  44. if (getLocked || now > RedisHelper.Get<long>(key) && now > RedisHelper.GetSet<long>(key, lock_time))
  45. {
  46. getLocked = true;
  47. }
  48. else
  49. {
  50. Thread.Sleep(30);
  51. }
  52. }
  53. }
  54. catch (Exception ex)
  55. {
  56. Console.WriteLine(ex.Message);
  57. }
  58. return getLocked;
  59. }
  60. }
  61. }

相关文档:https://redis.io/commands/setnx

原文链接:http://www.cnblogs.com/rohmeng/p/11397476.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号