.net core WebApi Monitor实现并发同步

在.net中,还可以使用Monitor实现线程并发同步。Monitor类是纯托管且完全可移植,并且可能会在操作系统资源需求方面更加高效。

Monitor的锁对象尽可能使用引用对象,如果是字符串或值对象,会出现引发SynchronizationLockException异常。

其实我们日常用的lock锁同步,其原理就是基于Monitor的。

即:

public static readonly object locker=new object();
lock(locker){
    //to do something
}

和以下代码是一样的意思:

public static readonly object locker=new object();
try{
    Monitor.Enter(locker);

    //to do something
}finally{
    Monitor.Exit(locker);
}

以下是基于测试的代码:

        protected static readonly object _locker = new object();
[HttpGet(
"[controller]/api/[action]")] public IActionResult Test() { int threadId = Thread.CurrentThread.ManagedThreadId; ResponseModel rc = new ResponseModel(0, $"{threadId} 初始化"); try { //独占资源锁 Monitor.Enter(_locker); int count = RedisHelper.GetAsync(RTestKey).Result.ToInt32(); if (count > 0) { if (RedisHelper.SetAsync(RTestKey, "-1").Result) rc.SetMessage($"{threadId} 设置成功!"); } else rc.SetMessage($"{threadId} 已被设置,不能再次设置!"); } catch (Exception ex) { _log.Error(ex); } finally { //释放锁,让其他线程获取锁并进入该方法 Monitor.Exit(_locker); } return Json(rc); }

接下来通过测试程序连续发送8次请求,看看结果:

通过以上操作,证明可以使用Monitor实现多线程的并发同步操作。

如果在执行了Monitor.Enter(locker)之后,需要释放锁对象并阻塞当前线程,让其他线程获取锁并执行的话,可以使用Monitor.Wait()方法。Monitor.Wait()方法的作用就是释放当前线程持有的锁,让当前线程进入等待队列,让其他某个线程获取锁对象并进入就绪状态并执行。其他线程执行Monitor.Pulse或PulseAll方法之后,当前等待的线程就可以继续获取锁并进入就绪队列去执行。

Monitor的Wait、Pulse和PulseAll方法必须在Enter和Exit方法之间调用。

如下测试代码:

        static void Func1() {
            Monitor.Enter(_locker);
            for(int i = 1; i < 5; i++)
            {                
                Console.Write($"=>Func1【{i}】");
                Monitor.Pulse(_locker);
                Monitor.Wait(_locker);
            }           
            
            Monitor.Exit(_locker);
        }

        static void Func2()
        {
            Monitor.Enter(_locker);
            for (int i = 1; i < 5; i++)
            {
                Monitor.Wait(_locker);
                Console.Write($"=>Func2【{i}】");
                Monitor.Pulse(_locker);               
            }

            Monitor.Exit(_locker);
        }     

        static void Func4() {
            List<Task> list = new List<Task>{
                Task.Factory.StartNew(Func1),
                Task.Factory.StartNew(Func2)                
            };

            Task.WaitAll(list.ToArray());
        }

        public static readonly object _locker = new object();
        static void Main(string[] args)
        {
            Func4();
        }

这段代码的目的是Fun1函数执行一次后,Fun2函数再执行一次,依次循环。让我们看看执行的结果:

由此看来,达到了本次测试的目的。

原文地址:https://www.cnblogs.com/williamwsj/p/9715849.html