.net 6 基于Redis的单机分布式锁

控制台例子:

1. Nuget包管理器添加 StackExchange.Redis 

说明: 单机的意思说Redis只存在于某一台服务器上,不考虑集群或者主从部署的情况

2.代码如下:

using StackExchange.Redis;
using System;


ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost,password=000415");
IDatabase db = redis.GetDatabase();


//redis键名
string resource = "myResourceName";

//锁的令牌
string lockToken = Guid.NewGuid().ToString();

//过期时间
TimeSpan expiry = TimeSpan.FromSeconds(5);

//并发数
int ct = 500;

var tasks = new Task[ct];
for (int i = 0; i < ct; i++)
{
    int client = (i + 1);
    tasks[i] = Task.Run(async () =>
    {
        while (true)
        {
            //获得锁
            if (await db.LockTakeAsync(resource, lockToken, expiry))
            {
                Console.WriteLine($"{DateTime.Now.ToString("HH:mm:ss:fff")} ********************************* 客户端{client} 创建了锁 ********************************* ");

                //开启异步线程,定时2秒延长锁
                var cancellationTokenSource = new CancellationTokenSource();
                var extendLockTask = Task.Run(async () =>
                {
                    while (true)
                    {
                        await Task.Delay(TimeSpan.FromSeconds(2), cancellationTokenSource.Token);
                        bool extended = await db.LockExtendAsync(resource, lockToken, expiry);
                        if (extended)
                        {
                            Console.WriteLine($"{DateTime.Now.ToString("HH:mm:ss:fff")} --------------- 客户端{client} 已延长了锁 ---------------");
                        }
                        else
                        {
                            Console.WriteLine($"{DateTime.Now.ToString("HH:mm:ss:fff")}--------------- 客户端{client} 延长了锁失败!---------------");
                            break;
                        }
                    }
                }, cancellationTokenSource.Token);

                // 模拟偶发任务耗时
                if ((client % 5) == 0)
                {
                    await Task.Delay(5000); // 如果 client 是 5 的倍数,则延时 5 秒
                }
                else
                {
                    await Task.Delay(60); // 否则延时 60 毫秒
                }

                //取消延长
                cancellationTokenSource.Cancel();
                try
                {
                    await extendLockTask;
                }
                catch (OperationCanceledException)
                {
                    //Console.WriteLine($"{DateTime.Now.ToString("HH:mm:ss:fff")}--------------- 客户端{client} 延长任务取消!---------------");
                }

                //释放锁
                await db.LockReleaseAsync(resource, lockToken);
                Console.WriteLine($"{DateTime.Now.ToString("HH:mm:ss:fff")} ********************************* 客户端{client} 释放了锁 ********************************* ");
                break;
            }
            else
            {
                // 获取锁失败以后随机等待一段时间后重试
                int delayMilliseconds = new Random().Next(50, 500); // 随机生成一个等待时间
                await Task.Delay(delayMilliseconds);
            }
        }
    });
}

Task.WaitAll(tasks);


Task.WaitAll(tasks);
Console.WriteLine("按下回车键停止...");
Console.ReadLine();

  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用 Redis 实现分布式锁的代码示例可以如下所示```csharp using StackExchange.Redis; using System; public class RedisDistributedLock { private readonly ConnectionMultiplexer _redis; private readonly IDatabase _database; public RedisDistributedLock(string connectionString) { _redis = ConnectionMultiplexer.Connect(connectionString); _database = _redis.GetDatabase(); } public bool AcquireLock(string lockKey, TimeSpan expiryTime, out string lockValue) { lockValue = Guid.NewGuid().ToString(); return _database.StringSet(lockKey, lockValue, expiryTime, When.NotExists); } public bool ReleaseLock(string lockKey, string lockValue) { return _database.ScriptEvaluate( LuaScript.Prepare( "if redis.call('get', KEYS[1]) == ARGV[1] then " + " return redis.call('del', KEYS[1]) " + "else " + " return 0 " + "end"), new RedisKey[] { lockKey }, new RedisValue[] { lockValue } ).Equals(1L); } } ``` 在上面的代码中,我们使用 StackExchange.Redis 库来连接 Redis 数据库。`AcquireLock` 方法用于获取分布式锁,`ReleaseLock` 方法用于释放分布式锁。 使用示例: ```csharp using System; public class Program { public static void Main() { var connectionString = "your_redis_connection_string"; var lockKey = "my_lock_key"; var expiryTime = TimeSpan.FromSeconds(30); using (var redisDistributedLock = new RedisDistributedLock(connectionString)) { string lockValue; if (redisDistributedLock.AcquireLock(lockKey, expiryTime, out lockValue)) { try { // 执行需要加锁的逻辑 Console.WriteLine("Lock acquired. Performing critical section..."); // 在这里执行需要加锁的操作 // 模拟操作耗时 System.Threading.Thread.Sleep(TimeSpan.FromSeconds(5)); Console.WriteLine("Critical section completed."); } finally { redisDistributedLock.ReleaseLock(lockKey, lockValue); } } else { Console.WriteLine("Failed to acquire lock."); } } } } ``` 上述代码中,我们使用一个唯一的 `lockValue` 来标识锁的持有者。在 `AcquireLock` 方法中,我们使用 Redis 的 `StringSet` 方法来尝试将锁的键值对写入 Redis,并设置过期时间和条件 `When.NotExists`(只有当键不存在时才设置成功)。在 `ReleaseLock` 方法中,我们使用 Lua 脚本来判断当前锁是否属于当前持有者,并通过 `ScriptEvaluate` 方法执行脚本。 请注意,这只是一个简单的示例代码,实际应用中可能需要处理更多的情况,比如锁的续期、异常处理等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值