在开发中遇到问题、技术点、解决方法、技术拓展、原理深究,把这些解决过程作为随笔记录下来。所以就有笔记系列,持续更新……
认真探究多线程前,只会new Thread;锁?Lock;线程等待?Thread.Sleep()。
例如 Thread.Sleep()、Thread.SpinWait();、{某种锁}.WaitOne() 等。
这些等待会影响代码的算法逻辑和程序的性能,也有可能会造成死锁,在本篇探究线程中等待。
三种常用等待
这三种等待分别是:
- Thread.Sleep();
- Thread.SpinWait();
- Task.Delay();
函数 | 注解 |
Thread.Sleep(); | 会阻塞线程,使得线程交出时间片,然后处于休眠状态,直至被重新唤醒; 适合用于长时间的等待; |
Thread.SpinWait(); | 使用了自旋等待,等待过程中会进行一些的运算,线程不会休眠,用于微小的时间等待; 长时间等待会影响性能; |
Task.Delay(); | 用于异步中的等待。 |
这里我们还需要继续 SpinWait 和 SpinLock 这两个类型,最后再进行总结对照。
SpinLock 结构
属性和方法
SpinLock 常用属性和方法如下:
属性:
属性 | 说明 |
IsHeld | 获取锁当前是否已由任何线程占用。 |
IsHeldByCurrentThread | 获取锁是否已由当前线程占用。 |
IsThreadOwnerTrackingEnabled | 获取是否已为此实例启用了线程所有权跟踪。 |
方法:
方法 | 说明 |
Enter(Boolean) | 采用可靠的方式获取锁,这样,即使在方法调用中发生异常的情况下, 都能采用可靠的方式检查 lockTaken 以确定是否已获取锁。 |
Exit() | 释放锁。 |
Exit(Boolean) | 释放锁。 |
TryEnter(Boolean) | 尝试采用可靠的方式获取锁,这样,即使在方法调用中发生异常的情况下, 都能采用可靠的方式检查 lockTaken 以确定是否已获取锁。 |
TryEnter(Int32, Boolean) | 尝试采用可靠的方式获取锁,这样,即使在方法调用中发生异常的情况下, 都能采用可靠的方式检查 lockTaken 以确定是否已获取锁。 |
TryEnter(TimeSpan, Boolean) | 尝试采用可靠的方式获取锁,这样,即使在方法调用中发生异常的情况下, 都能采用可靠的方式检查 lockTaken 以确定是否已获取锁。 |
示例
SpinLock 的模板如下:
private static void DoWork()
{
SpinLock spinLock = new SpinLock();
bool isGetLock = false; // 是否已获得了锁
try
{
spinLock.Enter(ref isGetLock);// 运算
}
finally
{
if (isGetLock)
spinLock.Exit();
}
}
Thread.Sleep() 会发生上下文切换,出现比较大的性能损失。