Thursday, March 17, 2005

My Singleton Answer

In my previous post I asked a question about using the singleton pattern for application-wide services that were stored in an object repository. With the help of the commenters, I decided not to implement the singleton pattern in this situation because since the services were only accessed via shared members on the object repository there is no need to force the service classes into the singleton pattern. This also makes them easier to extend (inherit).

That said, the discussion led to the question about how to implement lazy initialization of shared members in a thread-safe manner. I mentioned I was using double-checked locking, but someone pointed me to this interestering article and this discussion. I decided to test out double-checked locking versus just locking before the read in my distributed app (basically just created a remoted unit test) and I observed no difference in performance really. The test was just the "give me a warm and fuzzy feeling" test so I didn't write any performance counters or anything. But just measuring speed of the calls with 40 concurrent threads calling the components 100 times I only saw between a 1 and 10 milisecond average difference in speed. This is really nothing to me so I'm going to go with the easier, safer pattern of locking the whole shee-bang:
Private Shared m_service1 As ExtendedService
Private Shared _syncRoot As New Object

Public Shared ReadOnly Property Service1() As ExtendedService
  Get
    SyncLock (_syncRoot)
      If (m_service1 Is Nothing) Then
        m_service1 = Factory.CreateExtendedService()
      End If
    End SyncLock
    Return m_service1
  End Get
End Property

No comments: