在开发中遇到问题、技术点、解决方法、技术拓展、原理深究,把这些解决过程作为随笔记录下来。所以就有笔记系列,持续更新……

认真探究多线程前,只会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() 会发生上下文切换,出现比较大的性能损失。