原理
每个redis 客户端通过自己专有 random_value 只能通过random_value 解锁
-
为了防止出现异常而无法释放锁,所以加上过期时间
-
SET lock_key random_value NX PX 5000
random_value 是客户端生成的唯一的字符串。 NX 代表只在键不存在时,才对键进行设置操作。 PX 5000 设置键的过期时间为5000毫秒。
-
引入 StackExchange.Redis 包
using System;
using System.Threading;
using System.Threading.Tasks;
using StackExchange.Redis;
namespace redis分布式锁的实现
{
class Program
{
static ConnectionMultiplexer cun= ConnectionMultiplexer.Connect("localhost");
static IDatabase db = cun.GetDatabase(0);
static void Main(string[] args)
{
for (int i = 0; i < 5; i++)
{
ThreadPool.QueueUserWorkItem(new WaitCallback((t) =>
{
string Randomval = Guid.NewGuid().ToString();
if (RedisLock(Randomval))
{
Console.WriteLine(Randomval+"我竞争到锁了!!!");
try
{
db.StringSet("Number", 1);
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
//释放锁
RedisUnlocla(Randomval);
}
else
{
Console.WriteLine(Randomval+"获取锁失败");
}
}));
}
Console.Read();
}
static void MainAsync()
{
}
//执行加锁
public static bool RedisLock(String id,int retrycount=99)
{
while (retrycount-->0)
{
//db.StringSet("name", "zhang1san");
//设置最晚30秒过期
//SET lock_key random_value NX PX 5000
// random_value 是客户端生成的唯一的字符串。
// NX 代表只在键不存在时,才对键进行设置操作。
// PX 5000 设置键的过期时间为5000毫秒。
if (db.StringSet("lock_key", id, TimeSpan.FromMinutes(5000), When.NotExists))
{
//获取到了锁
return true;
}
}
return false;
}
/// <summary>
/// 解锁
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public static bool RedisUnlocla(String id)
{
//执行一段lua脚本
String script =
"if redis.call('get',KEYS[1]) == ARGV[1] then" +
" return redis.call('del',KEYS[1]) " +
"else" +
" return 0 " +
"end";
RedisKey[] keys = {new RedisKey("lock_key")};
RedisValue[] val = {new RedisValue(id)};
Console.WriteLine(db.ScriptEvaluate(script, keys, val));
return false;
}
}
}