zoukankan      html  css  js  c++  java
  • 学习 Monitor使用

    准备类:

    OperationItem
        public class OperationItem
        {
            public int Num { get; set; }
    
            public bool HasInit { get; set; }
    
            public void Add(int number)
            {
                Num += number;
                Debug.Print("{0}| add......{1}", DateTime.Now.ToString("hh:mm:ss fff"), Num);
                Thread.Sleep(1000);
            }
    
            public void Init(int number)
            {
                if (this.HasInit) return;
                Num = number;
                Debug.Print("{0}| init......{1}", DateTime.Now.ToString("hh:mm:ss fff"), Num);
                Thread.Sleep(1000);
                this.HasInit = true;
            }
        }

    场合1:必须先执行Init方法,后执行add方法,init和add在不同的线程中。

    先Init后Add
            OperationItem item = new OperationItem();
    
            private void button1_Click(object sender, RoutedEventArgs e)
            {
                Thread thread1 = new Thread(new ThreadStart(InitOperation));
                thread1.Name = "thread1";
                thread1.Start();
    
                Thread thread2 = new Thread(new ThreadStart(AddOperation));
                thread2.Name = "thread2";
                thread2.Start();
    
            }
    
            void AddOperation()
            {
                Monitor.Enter(item);
                item.Add(200);
                Monitor.Exit(item);
            }
    
            void InitOperation()
            {
                Monitor.Enter(item);
                item.Init(100);
                Monitor.Exit(item);
            }

    或者使用lock更清爽

    Lock写法
            OperationItem item = new OperationItem();
    
            private void button1_Click(object sender, RoutedEventArgs e)
            {
                Thread thread1 = new Thread(new ThreadStart(InitOperation));
                thread1.Name = "thread1";
                thread1.Start();
    
                Thread thread2 = new Thread(new ThreadStart(AddOperation));
                thread2.Name = "thread2";
                thread2.Start();
    
            }
    
            void AddOperation()
            {
                lock (item)
                {
                    item.Add(200);
                }
    
            }
    
            void InitOperation()
            {
                lock (item)
                {
                    item.Init(100);
                }
            }

    看看日志:

    02:45:27 231| init......100

    The thread 'thread1' (0x17b8) has exited with code 0 (0x0).

    02:45:28 237| add......300

    The thread 'thread2' (0x1110) has exited with code 0 (0x0).

    如果没有lock或者Monitor

    02:46:36 152| add......300

    02:46:36 152| init......300

    The thread 'thread2' (0x1410) has exited with code 0 (0x0).

    The thread 'thread1' (0x15a8) has exited with code 0 (0x0).

    这不乱套了吗,所以还是lock吧。

    场合2:Init方法有可能被多次调用,但是需求决定Init只能执行一次。
    init方法本身要加上判断,另外线程里面也要控制。

    Monitor
     private void button2_Click(object sender, RoutedEventArgs e)
            {
                Thread thread1 = new Thread(new ParameterizedThreadStart(InitOperation2));
                thread1.Name = "thread1";
                thread1.Start(200);
    
                Thread thread2 = new Thread(new ParameterizedThreadStart(InitOperation2));
                thread2.Name = "thread2";
                thread2.Start(500);
            }
    
            void InitOperation2(object data)
            {
                if (data == null) return;
                int ret = 0;
                Int32.TryParse(data.ToString(), out ret);
    
                //Monitor.Enter(item);
                //item.Init(ret);
                //Monitor.Exit(item);
    
                lock (item)
                {
                    item.Init(ret);
                }
            }

    日志:

    02:50:46 234| init......200

    The thread 'thread1' (0x3fc) has exited with code 0 (0x0).

    The thread 'thread2' (0x93c) has exited with code 0 (0x0).

    如果没有lock,悲剧了:

    02:51:05 631| init......500

    02:51:05 631| init......500

    The thread 'thread1' (0x8e0) has exited with code 0 (0x0).

    The thread 'thread2' (0xa04) has exited with code 0 (0x0).

    场合3:对于耗时操作,我们的耐心是有限的,设置等待超时。

     1    private void button3_Click(object sender, RoutedEventArgs e)
     2         {
     3             Thread thread1 = new Thread(new ParameterizedThreadStart(InitOperation3));
     4             thread1.Name = "thread1";
     5             thread1.Start(200);
     6 
     7             Thread thread2 = new Thread(new ParameterizedThreadStart(InitOperation3));
     8             thread2.Name = "thread2";
     9             thread2.Start(500);
    10         }
    11 
    12         void InitOperation3(object data)
    13         {
    14             if (data == null) return;
    15             int ret = 0;
    16             Int32.TryParse(data.ToString(), out ret);
    17 
    18             if (Monitor.TryEnter(item, 1200))
    19             {
    20                 item.Add(ret);
    21                 Monitor.Exit(item);
    22             }
    23         }

     留意第18行的1200,意思是等待的时间是1200毫秒,如果超出1200毫秒,就不执行了。

    Add方法执行时,

    线程会sleep1000毫秒,所以如果可以等待1200毫秒,还有戏,

    1200ms 执行日志:

    02:59:24 214| add......200

    The thread 'thread1' (0x1bb8) has exited with code 0 (0x0).

    02:59:25 220| add......700

    The thread 'thread2' (0x1b40) has exited with code 0 (0x0).

    如果只能等待800毫秒,那就没戏了,thread2直接退出。

    800ms 执行日志:

    03:00:11 219| add......200

    The thread 'thread2' (0x9cc) has exited with code 0 (0x0).

    The thread 'thread1' (0x1b2c) has exited with code 0 (0x0).

    场合4:虽然可以 加锁,但是有时候还是需要交叉执行。

     解释一下:

    a.线程1执行add方法,执行前,要确保已经执行了Init,所以必须等待Init执行完成

    b.线程2执行Init方法,尽管启动时间晚了两秒,但是启动后发现item的锁被让出,可以执行,所以马上Pulse,把Init的事情做了。

    c.在线程2 Pulse的时候,线程1已经知道了线程有动静了,所以准备出动。

    d.线程2 wait后,线程1马上拿过指挥权,继续完成它的工作。

     1 private void button4_Click(object sender, RoutedEventArgs e)
     2         {
     3             Thread thread1 = new Thread(new ParameterizedThreadStart(InitOperation4));
     4             thread1.Name = "thread1";
     5             thread1.Start(200);
     6             Debug.Print("{0}| start......{1}", DateTime.Now.ToString("hh:mm:ss fff"), thread1.Name);
     7             Thread.Sleep(2000);
     8 
     9             Thread thread2 = new Thread(new ParameterizedThreadStart(InitOperation4_1));
    10             thread2.Name = "thread2";
    11             Debug.Print("{0}| start......{1}", DateTime.Now.ToString("hh:mm:ss fff"), thread2.Name);
    12             thread2.Start(500);
    13         }
    14 
    15         void InitOperation4(object data)
    16         {
    17             if (data == null) return;
    18             int ret = 0;
    19             Int32.TryParse(data.ToString(), out ret);
    20 
    21             lock (item)
    22             {
    23                 Monitor.Wait(item);
    24                 item.Add(ret);
    25                 Monitor.Pulse(item);
    26             }
    27             Debug.Print("{0}| finish ......{1}", DateTime.Now.ToString("hh:mm:ss fff"), "InitOperation4");
    28         }
    29 
    30         void InitOperation4_1(object data)
    31         {
    32             if (data == null) return;
    33             int ret = 0;
    34             Int32.TryParse(data.ToString(), out ret);
    35 
    36             lock (item)
    37             {
    38                 Monitor.Pulse(item);
    39                 item.Init(ret);
    40                 Monitor.Wait(item);
    41             }
    42             Debug.Print("{0}| finish ......{1}", DateTime.Now.ToString("hh:mm:ss fff"), "InitOperation4_1");
    43         }

     所以,日志是:

    03:05:35 215| start......thread1

    03:05:37 242| start......thread2

    03:05:37 246| init......500

    03:05:38 247| add......700

    03:05:39 249| finish ......InitOperation4

    The thread 'thread1' (0xa84) has exited with code 0 (0x0).

    03:05:39 249| finish ......InitOperation4_1

    The thread 'thread2' (0x1310) has exited with code 0 (0x0).

    结束:

    Monitor真是个好东西呀,欢迎拍砖!

    Demo在这里: https://files.cnblogs.com/xiaokang088/WpfMonitor.zip

    另外,这位仁兄的解释更加清晰:http://hi.baidu.com/luoyuonline/blog/item/b10dfbeb56cd35d8d539c9ac.html

  • 相关阅读:
    URLOS用户福利:申请免费的泛域名(通配符域名)SSL证书
    主机管理面板LuManager以Apache2协议开源发布,可用作商业用途
    微服务设计概览
    使用SpringBoot搭建Web项目
    公共方法整合(四)数组相关
    阿里云短信整合封装类库
    高德地图接口使用整理
    公共方法整合(三)时间相关方法
    PHP 服务端友盟推送
    html 录音并上传
  • 原文地址:https://www.cnblogs.com/xiaokang088/p/2491782.html
Copyright © 2011-2022 走看看