redis分布式锁

DistributedMonitor:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DistLocker
{
    using StackExchange.Redis;
    using System;
    using System.Threading.Tasks;

    public static class DistributedMonitor
    {
        private static readonly Lazy<ConnectionMultiplexer> _redis = new Lazy<ConnectionMultiplexer>(() =>
            ConnectionMultiplexer.Connect("localhost:6379"));

        private static IDatabase Database => _redis.Value.GetDatabase();

        // 默认锁过期时间(防止死锁)
        private static readonly TimeSpan DefaultLockExpiry = TimeSpan.FromSeconds(30);

        /// <summary>
        /// 尝试进入分布式锁,最多等待指定时间。
        /// </summary>
        public static async Task<string> EnterAsync(string key, TimeSpan timeout)
        {
            if (string.IsNullOrWhiteSpace(key)) throw new ArgumentException("Key cannot be empty", nameof(key));

            var token = Guid.NewGuid().ToString();
            var endTime = DateTime.UtcNow + timeout;

            while (DateTime.UtcNow < endTime)
            {
                bool lockAcquired = await Database.StringSetAsync(
                    key,
                    token,
                    DefaultLockExpiry,
                    When.NotExists
                );

                if (lockAcquired)
                {
                    return token; // 成功获得锁
                }

                await Task.Delay(50); // 等待再尝试
            }

            return null; // 超时未获得锁
        }

        /// <summary>
        /// 释放锁(仅当当前token匹配时才删除)
        /// </summary>
        public static async Task<bool> ExitAsync(string key, string token)
        {
            if (string.IsNullOrWhiteSpace(key)) throw new ArgumentException("Key cannot be empty", nameof(key));
            if (string.IsNullOrWhiteSpace(token)) throw new ArgumentException("Token cannot be empty", nameof(token));

            RedisValue currentToken = await Database.StringGetAsync(key);
            if (currentToken == token)
            {
                return await Database.KeyDeleteAsync(key);
            }

            return false; // 锁不属于当前请求者,无法释放
        }
    }
}

  使用:

using DistLocker;
using System;
using System.Threading.Tasks;

class Program
{
    static async Task Main(string[] args)
    {
        string key = "distributed_lock_key";
        TimeSpan timeout = TimeSpan.FromSeconds(10);

        Console.WriteLine("尝试获取锁...");
        string token = await DistributedMonitor.EnterAsync(key, timeout);

        if (token != null)
        {
            try
            {
                Console.WriteLine("成功获取锁,执行临界区操作...");

                // 模拟业务逻辑处理
                await Task.Delay(2000);

                Console.WriteLine("临界区执行完毕");
            }
            finally
            {
                bool released = await DistributedMonitor.ExitAsync(key, token);
                Console.WriteLine(released ? "锁已释放" : "锁释放失败或已被其他客户端释放");
            }
        }
        else
        {
            Console.WriteLine("未能在指定时间内获取到锁");
        }

        Console.WriteLine("程序结束");

        Console.ReadLine();
    }
}

  

posted @ 2025-06-16 10:39  China Soft  阅读(11)  评论(0)    收藏  举报