我想用Redis做分布式锁。我为此使用 RedLock.net nuget 包。 但是线程能够获取锁,即使另一个线程已经获取了锁。
这是示例代码:
public void Demo(RedLockFactory redLockFactory)
{
Parallel.For(0, 5, x =>
{
TimeSpan expiry = TimeSpan.FromSeconds(30);
var wait = TimeSpan.FromSeconds(10);
var retry = TimeSpan.FromSeconds(1);
string user = $"User:{x}";
using (var redLock = redLockFactory.CreateLock(resource, expiry, wait, retry))
{
// make sure we got the lock
if (redLock.IsAcquired)
{
Console.WriteLine($"{user} acquired lock at {DateTimeOffset.Now.ToString("dd-MM-yyyy HH:mm:ss")}.");
}
else
{
Console.WriteLine($"{user} didn't get the lock.");
}
}
});
}
这是我的演示的输出
User:4 acquired lock at 06-10-2020 09:24:34.
User:2 acquired lock at 06-10-2020 09:24:34.
User:1 acquired lock at 06-10-2020 09:24:34.
User:0 acquired lock at 06-10-2020 09:24:35.
User:3 acquired lock at 06-10-2020 09:24:35.
如您所见,每个线程都能够获取锁,这是不应该发生的。
一旦获取锁,其他线程就不能获取锁。
Per RedLock.net/README.md,“锁在 using 块结束时自动释放”。
所以我认为您的演示输出中发生的情况是:
using
块,释放其锁(现在另一个线程可以获胜)如果您想看到锁获取失败,请在退出
using
块之前执行非常慢的操作(>10 秒)。出于演示目的,您可以在写完“acquired”行后Thread.Sleep(15000)
。
这里是 RedLock.Net 的一个更好的示例测试。 使用的时间跨度适用于我的应用程序。 每个线程最终都应该获得锁,但是您可以看到每个线程获取锁之间的等待时间。
public static void Main() {
List<RedLockEndPoint> endPoints = [
new DnsEndPoint("localhost", 6379)
];
RedLockFactory redLockFactory = RedLockFactory.Create(endPoints);
Parallel.For(0, 10, x => {
TimeSpan expiry = TimeSpan.FromSeconds(120);
TimeSpan wait = TimeSpan.FromSeconds(60);
TimeSpan retry = TimeSpan.FromSeconds(5);
using IRedLock? redLock = redLockFactory.CreateLock("123456", expiry, wait, retry);
if (redLock.IsAcquired) {
Console.WriteLine($"User:{x} acquired lock at {DateTimeOffset.Now:dd-MM-yyyy HH:mm:ss}.");
Task.Delay(500 * x).GetAwaiter().GetResult();
}
else {
Console.WriteLine($"User:{x} didn't get the lock.");
}
});
}