·引用地址:.Netcore 使用CSRedis Lock分布式加锁原理_csredisclientlock_FameLee-的博客-CSDN博客
订阅专栏
1.//使用方法
using (var Lock = RedisHelper.Lock("锁名", "过期时间"))//返回CSRedisClientLock方法
{
if (Lock == null)
{
return new Response<bool>().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<object> { 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);
}
}
/// <summary>
/// 释放分布式锁
/// </summary>
/// <returns>成功/失败</returns>
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.加锁失败返回错误。
————————————————
版权声明:本文为CSDN博主「FameLee-」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_40138785/article/details/122124460