You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为.NET Core 5中MediatR的瞬时服务添加线程锁?

.NET Core 5中MediatR处理器锁失效的修复方案

我在.NET Core 5中使用MediatR处理任务时,尝试添加线程锁但未生效,原因是MediatR默认的处理器并非单例服务,每个请求都会创建新的处理器实例,导致锁对象无法共享。

我的处理器代码如下:

public class MyCommandHandler : IRequestHandler<MyCommand, bool>
{
  private object thisLock = new();
  private readonly IService _service;

  public MyCommandHandler(IService service)
  {
      _service = service;
  }

  public async Task<bool> Handle(MyCommand request, CancellationToken cancellationToken)
  {
     var items = _service.Get().Result;
     lock (thisLock)
     {
        // 需同步的业务逻辑
        await _service.Add(new Foo{ Id = 1 });   
     }
  }
}

Startup配置:

services.AddMediatR(Assembly.GetExecutingAssembly());
services.AddSingleton<IService , MyService >();

我曾尝试将处理器注册为单例,但因写法错误出现运行时错误:

services.AddSingleton(typeof(IRequestHandler<,>), typeof(IRequestHandler<MyCommand, bool>));

以下是几种可行的修复方案:

方案1:将锁对象移至单例服务中

由于IService已注册为单例,可将锁对象内置到MyService中,确保所有处理器实例共享同一锁:

修改MyService代码:

public class MyService : IService
{
    private readonly object _lockObj = new();

    public async Task Add(Foo foo)
    {
        lock (_lockObj)
        {
            // 执行需要同步的逻辑
            // 注意:若包含异步操作,lock会阻塞线程,建议改用SemaphoreSlim
        }
    }

    // 其他业务方法...
}

如果Add方法包含异步操作,推荐使用SemaphoreSlim支持异步等待,避免线程阻塞:

public class MyService : IService
{
    private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);

    public async Task Add(Foo foo)
    {
        await _semaphore.WaitAsync();
        try
        {
            // 异步业务逻辑
        }
        finally
        {
            _semaphore.Release();
        }
    }
}

方案2:正确将MediatR处理器注册为单例

之前的单例注册写法错误,需直接注册具体的处理器类型为单例:

修改Startup中的MediatR注册代码:

services.AddMediatR(cfg => 
{
    cfg.RegisterServicesFromAssembly(Assembly.GetExecutingAssembly());
    // 将指定处理器注册为单例
    cfg.AddSingletonHandler<MyCommandHandler>();
});

// 或单独注册处理器:
services.AddSingleton<IRequestHandler<MyCommand, bool>, MyCommandHandler>();

注册完成后,处理器会以单例形式存在,thisLock会被所有请求共享,锁即可生效。注意:若处理器内存在其他非线程安全的状态,需确保其线程安全性。

方案3:使用全局静态锁对象

在处理器类中定义静态锁对象,无论处理器是否为单例,所有实例都会共享该锁:

public class MyCommandHandler : IRequestHandler<MyCommand, bool>
{
  private static readonly object _globalLock = new(); // 静态全局锁
  private readonly IService _service;

  public MyCommandHandler(IService service)
  {
      _service = service;
  }

  public async Task<bool> Handle(MyCommand request, CancellationToken cancellationToken)
  {
     var items = await _service.Get(); // 建议用await替代.Result,避免死锁
     lock (_globalLock)
     {
        // 需同步的业务逻辑
        await _service.Add(new Foo{ Id = 1 });   
     }
  }
}

注意:静态锁是全局范围的,可能会影响其他无需同步的操作,需谨慎使用。另外,_service.Get().Result易引发死锁,建议替换为异步等待的await _service.Get()。

内容的提问来源于stack exchange,提问作者AshNawa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 09:27:28