以下のコードは、アプリケーションで使用するシングルトンを表しています。_MyObject = New Objectは、どのような状況でも複数回実行したくない、非常にコストのかかるデータベース呼び出しを表していると仮定しましょう。これが起こらないようにするために、最初に_MyObjectバッキング フィールドが null です。そうである場合は、SyncLock に割り込んで、一度に 1 つのスレッドだけがここに入ることができるようにします。ただし、シングルトンがインスタンス化される前に 2 つのスレッドが最初の null チェックを通過した場合、スレッド A がインスタンスを作成している間、スレッド B は SyncLock で待機することになります。スレッド A がロックを終了した後、スレッド B はロックに入り、インスタンスを再作成します。その結果、高価なデータベース呼び出しが行われます。これを防ぐために、ロック内で発生するバッキング フィールドの null チェックを追加しました。このようにして、スレッド B がロックで待機することに成功した場合、スレッド B は通過し、インスタンスを再作成しないことを確認するためにもう一度 null チェックを行います。
では、2 つの null チェックを行う必要は本当にあるのでしょうか? 外側の null チェックを取り除くことと、Synclock から始めることはまったく同じでしょうか? 言い換えれば、変数のスレッドロックは、複数のスレッドがバッキングフィールドに同時にアクセスできるようにするのと同じくらい高速ですか? その場合、外側の null チェックは不要です。
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