线程、任务和同步学习笔记(六)

时间:2022-07-25 18:30:59

1、如前所述,lock语句由编译器解析为Monitor类。Monitor类是一个静态类,有Enter和Exit方法。

 1 using System;
 2 using System.Text;
 3 using System.Threading;
 4 using System.Threading.Tasks;
 5 
 6 class Program
 7 {
 8     static void Main(string[] args)
 9     {
10         StringBuilder str = new StringBuilder();
11         new Task(() =>
12         {
13             for (int i = 0; i < 26; i++)
14             {
15                 str.Append(((char)('A' + i)).ToString()); 
16             }
17             str.Append("\n");
18         }).Start();
19         new Thread(() => 
20         {
21             for (int i = 0; i < 26; i++)
22             {
23                 str.Append(((char)('a' + i)).ToString());
24             }
25             str.Append("\n");
26         }).Start();
27         Console.WriteLine(str);
28         Console.WriteLine("End the main thread.");
29     }
30 }

运行结果:

线程、任务和同步学习笔记(六)

 将上述代码修改如下:

 1 using System;
 2 using System.Text;
 3 using System.Threading;
 4 using System.Threading.Tasks;
 5 
 6 class Program
 7 {
 8     static void Main(string[] args)
 9     {
10         object locker = new object();
11         StringBuilder str = new StringBuilder();
12         new Task(() =>
13         {
14             lock (locker)
15             {
16                 for (int i = 0; i < 26; i++)
17                 {
18                     str.Append(((char)('A' + i)).ToString()); 
19                 }
20             }
21             Console.WriteLine("{0} in thread {1}", str, Thread.CurrentThread.ManagedThreadId);
22         }).Start();
23         new Thread(() => 
24         {
25             lock (locker)
26             {
27                 for (int i = 0; i < 26; i++)
28                 {
29                     str.Append(((char)('a' + i)).ToString());
30                 }
31             }
32             Console.WriteLine("{0} in thread {1}", str, Thread.CurrentThread.ManagedThreadId);
33         }).Start();
34         Console.WriteLine("End the main thread.");
35     }
36 }

运行结果:

线程、任务和同步学习笔记(六)

使用Monitor类再一次将上述代码做如下修改:

 1 using System;
 2 using System.Text;
 3 using System.Threading;
 4 using System.Threading.Tasks;
 5 
 6 class Program
 7 {
 8     static void Main(string[] args)
 9     {
10         object locker = new object();
11         StringBuilder str = new StringBuilder();
12         new Task(() =>
13         {
14             while (true)
15             {
16                 Monitor.Enter(locker);
17                 try
18                 {
19                     for (int i = 0; i < 26; i++)
20                     {
21                         str.Append(((char)('A' + i)).ToString()); 
22                     }
23                     str.Append("\n");
24                     Console.WriteLine("{0} in thread {1}", str.ToString(), Thread.CurrentThread.ManagedThreadId);
25                 }
26                 finally
27                 {
28                     Monitor.Exit(locker);
29                 }
30             }
31         }).Start();
32         new Thread(() => 
33         {
34             while (true)
35             {
36                 Monitor.Enter(locker);
37                 try
38                 {
39                     for (int i = 0; i < 26; i++)
40                     {
41                         str.Append(((char)('a' + i)).ToString());
42                     }
43                     str.Append("\n");
44                     Console.WriteLine("{0} in thread {1}", str.ToString(), Thread.CurrentThread.ManagedThreadId);
45                 }
46                 finally
47                 {
48                     Monitor.Exit(locker);
49                 }
50             }
51         }).Start();
52         Console.WriteLine("End the main thread.");
53     }
54 }

运行结果:

线程、任务和同步学习笔记(六)

2、从运行结果可以看出,使用Monitor类可以完全取代lock语句。Monitor类的优势是可以使用TryEnter方法,该方法可以传递一个被锁定的超时值,从而避免无限等待,即避免死锁的现象发生。

 1 using System;
 2 using System.Text;
 3 using System.Threading;
 4 using System.Threading.Tasks;
 5 
 6 class Program
 7 {
 8     static void Main(string[] args)
 9     {
10         object locker = new object();
11         new Thread(() => 
12         {
13             Random random = new Random();
14             bool locked = false;
15             Monitor.TryEnter(locker, 200, ref locked);
16             if (locked)
17             {
18                 try
19                 {
20                     while (true)
21                     {
22                         int i = random.Next(5);
23                         Thread.Sleep(i);
24                         Console.WriteLine("{0} in thread {1}, {2}", DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss.fff"), Thread.CurrentThread.ManagedThreadId, i);
25                     }
26                 }
27                 finally
28                 {
29                     Monitor.Exit(locker);
30                 }
31             }
32             else
33             {
34                 Console.WriteLine("Not locked int thread {0}", Thread.CurrentThread.ManagedThreadId);
35             }
36         }).Start();
37         new Thread(() => 
38         {
39             Random random = new Random();
40             bool locked = false;
41             Monitor.TryEnter(locker, 200, ref locked);
42             if (locked)
43             {
44                 try
45                 {
46                     while (true)
47                     {
48                         int i = random.Next(5);
49                         Thread.Sleep(i);
50                         Console.WriteLine("{0} in thread {1}, {2}", DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss.fff"), Thread.CurrentThread.ManagedThreadId, i);
51                     }
52                 }
53                 finally
54                 {
55                     Monitor.Exit(locker);
56                 }
57             }
58             else
59             {
60                 Console.WriteLine("Not locked int thread {0}", Thread.CurrentThread.ManagedThreadId);
61             }
62         }).Start();
63     }
64 }

运行结果:

线程、任务和同步学习笔记(六)

3、SpinLock结构是.NET4新增的,其用法与Monitor类相似。

4、WaitHandle类是一个抽象类,可以等待一个信号的设置,因为它是基类,可以派生出多个类,可以等待不同的信号。