一. 监视锁(Monitor和lock)
1. Monitor类,限定线程个数的一把锁(Synchronized lock是他的语法糖),两个核心方法:
Enter:锁住某个资源。
Exit:退出某一个资源。
测试案例:开启5个线程同时对一个变量进行自增操作,结果变量有序的输出,说明该锁同时只允许一个线程访问。
但是写法很麻烦,每次都要try-catch-finally,还要声明bool变量。这个时候lock语法糖就很好的解决了这个问题。
代码实践:
1 static object lockMe = new object();2 {3 for (int i = 0; i < 5; i++)4 {5 Task.Factory.StartNew(() =>6 {7 for (int j = 0; j < 100; j++)8 {9 var b = false;
10 try
11 {
12 Monitor.Enter(lockMe, ref b);
13 Console.WriteLine(num++);
14 }
15 catch (Exception)
16 {
17
18 throw;
19 }
20 finally
21 {
22 if (b)
23 {
24 Monitor.Exit(lockMe);
25 }
26 }
27
28 }
29
30 });
31 }
32 }
2. lock语法糖
使用很简单,声明一个静态的object类型变量,调用lock语法糖,将共享变量放入其中,即可保证lock内同时只能一个线程访问。
代码实践:
1 {2 for (int i = 0; i < 5; i++)3 {4 Task.Factory.StartNew(() =>5 {6 for (int j = 0; j < 100; j++)7 {8 lock (lockMe)9 {
10 Console.WriteLine(num++);
11 }
12 }
13 });
14 }
15 }
二. 混合锁
1. 简介:混合锁=用户模式锁+内核模式锁,先在用户模式下内旋,如果超过一定的阈值,会切换到内核锁,在内旋模式下,我们会看到大量的Sleep(0),Sleep(1),Yield等语法。
Thread.Sleep(1) 让线程休眠1ms
Thread.Sleep(0) 让线程放弃当前的时间片,让本线程更高或者同等线程得到时间片运行。
Thread.Yield() 让线程立即放弃当前的时间片,可以让更低级别的线程得到运行,当其他thread时间片用完,本thread再度唤醒。
混合锁包括以下三种:ManualResetEventSlim、SemaphoreSlim、ReaderWriterLockSlim,这三种混合锁,要比他们对应的内核模式锁 (ManualResetEvent、Semaphore、ReaderWriterLock),的性能高的多。
2. ManualResetEventSlim
构造函数默认为false,可以使用Wait方法替代WaitOne方法,支持任务取消. (详细的代码同内核版本类似,这里不做测试了)
3. SemaphoreSlim
用法和内核版本类似,使用Wait方法代替WaitOne方法,Release方法不变。(详细的代码同内核版本类似,这里不做测试了)
4. ReaderWriterLockSlim
用法和内核版本类似,但是四个核心方法换成了:
锁读的两个核心方法:EnterReadLock、ExitReadLock。
锁写的两个核心方法:EnterWriteLock、ExitWriteLock。
(详细的代码同内核版本类似,这里不做测试了)