好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

学习 Monitor使用

学习 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  );
            }
        } 

看看日志:

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

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

如果没有lock或者Monitor

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);
            }
        } 

日志:

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

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

如果没有lock,悲剧了:

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 执行日志:

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

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

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

800ms 执行日志:

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          }

 所以,日志是:

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

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

http://www.cnblogs.com/xiaokang088/archive/2012/05/09/2491782.html

作者: Leo_wl

    

出处: http://www.cnblogs.com/Leo_wl/

    

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

版权信息

查看更多关于学习 Monitor使用的详细内容...

  阅读:87次