学习 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测试数据/xiaokang088/WpfMonitor.zip
另外,这位仁兄的解释更加清晰: http://hi.baidu测试数据/luoyuonline/blog/item/b10dfbeb56cd35d8d539c9ac.html
http://HdhCmsTestcnblogs测试数据/xiaokang088/archive/2012/05/09/2491782.html
作者: Leo_wl
出处: http://HdhCmsTestcnblogs测试数据/Leo_wl/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
版权信息