zoukankan      html  css  js  c++  java
  • C# 对象锁——Monitor

    Monitor里边有一些static方法,可以用于在对象上获取同步锁,来进行一些进程同步控制操作

    用法及注意点如下:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    
    namespace myTest
    {
        class Program
        {
            // 一个比较容易犯的错误
            // 使用   Monitor   锁定对象(即引用类型)而不是值类型。将值类型变量传递给   Enter   时,
            //它被装箱为对象。如果再次将相同的变量传递给   Enter,则它被装箱为一个单独对象,而且线程不会阻止。Monitor  
            //本应保护的代码未受保护。此外,将变量传递给   Exit   时,
            //也创建了另一个单独对象。因为传递给   Exit   的对象和传递给   Enter   的对象不同,Monitor   
            //将引发   SynchronizationLockException
            //这种情况最好用 Interlocked 来完成
            private static int _num = 1;
            // 装箱一下就可以了
            private static object num = _num;
            static void Main(string[] args)
            {
    
                Thread t1 = new Thread(new ThreadStart(addNum));
                t1.Name = "线程1";
                Thread t2 = new Thread(new ThreadStart(addNum));
                t2.Name = "线程2";
                t1.Start();
                t2.Start();
                Console.ReadLine();
            }
            //|- 拥有锁的线程 lockObj->|- 就绪队列(ready queue) |- 等待队列(wait queue)
            // 就绪队列:尝试lock对象的线程
            // 等待队列:在等待中, !!!不会主动!!!    去lock对象的线程  Monitor.wait 会使线程进入等待队列
            // 如果只调用wait不调用pulse,可能使线程进入死锁
            // 下面执行的时间线:  t1获得锁——t1打印——2000ms——t1Pulse(此时无线程在等待队列,故无效)——2000ms——t1释放锁并进入等待队列——
            //                 t2获得锁——t2打印——2000ms——t2Pulse(此时t1线程在等待队列,t1进入就绪队列)——2000ms——t2释放锁并进入等待队列——
            //                 t1获得锁——t1Pulse(此时t2线程在等待队列,t2进入就绪队列)——t1打印——t1释放锁——t1退出——
            //                 t2获得锁——t2Pulse(此时无线程在等待队列,故无效)——t2打印——t2释放锁——t2退出
            private static void addNum()
            {
                Boolean gotLock = false;
                try
                {
                    // Monitor.Enter(num); //获取排它锁
                    Monitor.Enter(num, ref gotLock);
                    Console.WriteLine(Thread.CurrentThread.Name+ DateTime.Now.ToString() + "——————" + num);
                    //释放锁并让线程进入等待队列,直到它重新获得锁
                    Thread.Sleep(2000);
                    //通知等待的线程进入就绪队列,有锁了
                    Monitor.Pulse(num);
                    Thread.Sleep(2000);
                    Monitor.Wait(num);
                    Monitor.Pulse(num);
                }
                finally
                {
                    Console.WriteLine(Thread.CurrentThread.Name + DateTime.Now.ToString() + "——————" + num);
                    if (gotLock)
                    {
                        Monitor.Exit(num);
                    }
                }
            }
        }
    }

    运行结果:

    用Monitor类获得对象锁的try .. catch finally的过程还有一个语法糖,lock关键字

  • 相关阅读:
    LeetCode Array Easy 414. Third Maximum Number
    LeetCode Linked List Medium 2. Add Two Numbers
    LeetCode Array Easy 283. Move Zeroes
    LeetCode Array Easy 268. Missing Number
    LeetCode Array Easy 219. Contains Duplicate II
    LeetCode Array Easy 217. Contains Duplicate
    LeetCode Array Easy 189. Rotate Array
    LeetCode Array Easy169. Majority Element
    LeetCode Array Medium 11. Container With Most Water
    LeetCode Array Easy 167. Two Sum II
  • 原文地址:https://www.cnblogs.com/tzyy/p/4746023.html
Copyright © 2011-2022 走看看