下面的代码代表我在我的应用程序中使用的单例。让我们假设它_MyObject = New Object
代表了一个非常昂贵的数据库调用,在任何情况下我都不想多次调用它。为了确保不会发生这种情况,我首先检查是否_MyObject
支持字段为空。如果是,我会闯入一个 SyncLock 以确保一次只有一个线程可以进入这里。但是,如果两个线程在单例实例化之前通过了第一次空检查,则线程 B 将最终坐在 SyncLock 处,而线程 A 创建实例。线程 A 退出锁后,线程 B 将进入锁并重新创建实例,这将导致进行昂贵的数据库调用。为了防止这种情况,我添加了对锁中发生的支持字段的额外空检查。这样,如果线程 B 设法最终在锁处等待,它将通过并再做一次空值检查,以确保它不会重新创建实例。
那么真的有必要做两次空检查吗?摆脱外部空检查并从 Synclock 开始是否会一样?换句话说,线程锁定变量是否与让多个线程同时访问支持字段一样快?如果是这样,外部空检查是多余的。
Private Shared synclocker As New Object
Private Shared _MyObject As Object = Nothing
Public Shared ReadOnly Property MyObject As Object
Get
If _MyObject Is Nothing Then 'superfluous null check?
SyncLock synclocker
If _MyObject Is Nothing Then _MyObject = New Object
End SyncLock
End If
Return _MyObject
End Get
End Property