栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

.Netcore 使用CSRedis Lock分布式加锁原理

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

.Netcore 使用CSRedis Lock分布式加锁原理

1.//使用方法

  using (var Lock = RedisHelper.Lock("锁名", "过期时间"))//返回CSRedisClientLock方法
            {
                if (Lock == null)
                {
                    return new Response().Fail("获取分布式锁失败");
                }
              //业务代码
            }//using结束默认调用CSRedisClientLock的Dispose方法,释放锁
2.//源代码分析

    public CSRedisClientLock Lock(string name, int timeoutSeconds, bool autoDelay = true)
        {
            name = $"CSRedisClientLock:{name}";
            var startTime = DateTime.Now;
            while (DateTime.Now.Subtract(startTime).TotalSeconds < timeoutSeconds)//通多过期时间循环去等待加锁
            {
                var value = Guid.NewGuid().ToString();
                if (this.Set(name, value, timeoutSeconds, RedisExistence.Nx) == true)//通过Redis Setnx设置锁也就是redis的 key value
                {
                    double refreshSeconds = (double)timeoutSeconds / 2.0;
                    return new CSRedisClientLock(this, name, value, timeoutSeconds, refreshSeconds, autoDelay);//返回CSRedisClientLock类
                }
                Thread.CurrentThread.Join(3);//加锁失败阻塞当前线程
            }
            return null;
        }
		
	public bool Set(string key, object value, TimeSpan expire, RedisExistence? exists = null)//通过Redis Setnx设置锁成功返回true失败返回false
        {
            object redisValule = this.SerializeRedisValueInternal(value);
            if (expire <= TimeSpan.Zero && exists == null) return ExecuteScalar(key, (c, k) => c.Value.Set(k, redisValule)) == "OK";
            if (expire <= TimeSpan.Zero && exists != null) return ExecuteScalar(key, (c, k) => c.Value.Set(k, redisValule, null, exists)) == "OK";
            if (expire > TimeSpan.Zero && exists == null) return ExecuteScalar(key, (c, k) => c.Value.Set(k, redisValule, expire, null)) == "OK";
            if (expire > TimeSpan.Zero && exists != null) return ExecuteScalar(key, (c, k) => c.Value.Set(k, redisValule, expire, exists)) == "OK";
            return false;
        }
		
    private static RedisStatus.Nullable Set(string key, object value, int? expirationSeconds = null, long? expirationMilliseconds = null, RedisExistence? exists = null)
        {
            var args = new List { key, value };
            if (expirationSeconds != null)
                args.AddRange(new[] { "EX", expirationSeconds.ToString() });
            if (expirationMilliseconds != null)
                args.AddRange(new[] { "PX", expirationMilliseconds.ToString() });
            if (exists != null)
                args.AddRange(new[] { exists.ToString().ToUpperInvariant() });// 通过Setnx设置锁
            return new RedisStatus.Nullable("SET", args.ToArray());
        }
		
public class CSRedisClientLock : IDisposable
    {

        CSRedisClient _client;
        string _name;
        string _value;
        int _timeoutSeconds;
        Timer _autoDelayTimer;

        public CSRedisClientLock(CSRedisClient rds, string name, string value, int timeoutSeconds, double refreshSeconds, bool autoDelay)
        {
            _client = rds;
            _name = name;
            _value = value;
            _timeoutSeconds = timeoutSeconds;
            if (autoDelay)
            {
                var refreshMilli = (int)(refreshSeconds * 1000);
                var timeoutMilli = timeoutSeconds * 1000;
                _autoDelayTimer = new Timer(state2 => Refresh(timeoutMilli), null, refreshMilli, refreshMilli);
            }
        }


        /// 
        /// 释放分布式锁
        /// 
        /// 成功/失败
        public bool Unlock()
        {
            _autoDelayTimer?.Dispose();
            return _client.eval(@"local gva = redis.call('GET', KEYS[1])
if gva == ARGV[1] then
  redis.call('DEL', KEYS[1])
  return 1
end
return 0", _name, _value)?.ToString() == "1";
        }

        public void Dispose() => this.Unlock();
    } 

CSRedis GitHub地址

3.分布式加锁流程
1.通过Redis Setnx加锁并设置过期时间。
2.如果锁不存在就加锁。
3.如果锁存在就通过join阻塞线程,循环等待加锁直至过期时间结束。
4.加锁成功后执行业务并释放锁。
5.加锁失败返回错误。

转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号