You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Threading.Thread.Sleep()抛出未捕获空引用异常问题排查

问题解答

1. Sleep()为何抛出未文档化异常?Threading.Thread是否可能为null?

  • Thread.Sleep()不会抛出空引用异常:根据.NET官方文档,Thread.Sleep(Int32)仅会在输入参数为负数时抛出ArgumentOutOfRangeException,不存在抛出NullReferenceException的场景。
  • Threading.Thread不可能为null:你调用的是Thread类的静态方法Sleep(),无需实例化Thread对象,因此不存在Thread实例为null的情况。
  • 空引用异常的真实根源:多线程竞态条件。在高并发场景下,WaitInQueue方法中虽然初始判断了instance.SessionData IsNot Nothing,但在代码执行过程中(比如Sleep()等待期间),其他线程(如处理同一Session的其他请求线程)可能将instance.SessionData置为null。当代码执行到NextInQueue = instance.SessionData.NextInQueue时,instance.SessionData已变为null,从而触发空引用异常——错误堆栈显示的行号正是这行代码,而非Sleep()调用。

2. try/catch为何无法捕获该异常?

异常未被捕获的核心原因是竞态条件导致异常发生在try块的覆盖盲区:

  • 原代码中,If instance.SessionData IsNot Nothing判断与try块之间存在时间窗口,此时其他线程可能将instance.SessionData置为null。当代码进入try块执行Dim NextInQueue = instance.SessionData.NextInQueue时,instance.SessionData已为null,抛出的异常本应被catch捕获,但在极端高并发场景下,线程上下文切换可能导致异常抛出时机超出预期;
  • 另一种极小概率情况是,Sleep()期间请求上下文被意外回收,导致instance对象状态被破坏,此时抛出的异常可能绕过常规try/catch逻辑。

修复方案

核心思路:消除竞态条件,确保SessionData访问的线程安全

由于MaintainQueue方法使用SyncLock Lock保证队列操作的线程安全,WaitInQueue中访问SessionData时也需同步锁,同时避免持有锁期间Sleep阻塞其他线程:

Private Sub WaitInQueue(key As Guid, instance As LmsInstance)
    SyncLock Lock
        Dim nextInQueue As Guid? = Nothing
        If instance.SessionData IsNot Nothing Then
            nextInQueue = instance.SessionData.NextInQueue
        End If

        While nextInQueue.HasValue AndAlso nextInQueue.Value <> key
            ' 释放锁后再Sleep,避免阻塞其他队列操作
            Monitor.Exit(Lock)
            Threading.Thread.Sleep(1)
            ' 重新获取锁,检查SessionData状态
            Monitor.Enter(Lock)
            If instance.SessionData Is Nothing Then
                Exit While ' Session已失效,直接退出等待
            End If
            nextInQueue = instance.SessionData.NextInQueue
        End While
    End SyncLock
End Sub

额外优化:增强异常捕获的覆盖率

调整try/catch块的范围,覆盖整个方法的核心逻辑,确保任何异常都能被捕获:

Private Sub WaitInQueue(key As Guid, instance As LmsInstance)
    Try
        SyncLock Lock
            Dim nextInQueue As Guid? = Nothing
            If instance.SessionData IsNot Nothing Then
                nextInQueue = instance.SessionData.NextInQueue
            End If

            While nextInQueue.HasValue AndAlso nextInQueue.Value <> key
                Monitor.Exit(Lock)
                Threading.Thread.Sleep(1)
                Monitor.Enter(Lock)
                If instance.SessionData Is Nothing Then
                    Exit While
                End If
                nextInQueue = instance.SessionData.NextInQueue
            End While
        End SyncLock
    Catch ex As Exception
        Serilog.Log.Logger.Warning(ex, "Exception in WaitInQueue for key {Key}", key)
    End Try
End Sub

内容的提问来源于stack exchange,提问作者Henrik R Clausen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 01:13:09