编程后端开发工程师 (VB.NET)

如何在Visual Basic中实现单例设计模式,在线程安全方面需要注意哪些事项,以及经典实现和懒惰(lazy)实现之间有什么区别?

用 Hintsage AI 助手通过面试

答案。

单例模式保证一个类只有一个实例,并提供对该实例的全局访问。在VB.NET中,通常使用私有构造函数和静态属性来存储单一实例:

Public Class Singleton Private Shared _instance As Singleton Private Sub New() ' 私有构造函数 End Sub Public Shared ReadOnly Property Instance() As Singleton Get If _instance Is Nothing Then _instance = New Singleton() End If Return _instance End Get End Property End Class

线程安全性: 在多线程环境中,可能会在同时访问时创建两个实例。解决方案:使用锁或Lazy(Of T)结构:

' 懒惰的线程安全实现 Public Class Singleton Private Shared ReadOnly _instance As New Lazy(Of Singleton)(Function() New Singleton()) Private Sub New() End Sub Public Shared ReadOnly Property Instance() As Singleton Get Return _instance.Value End Get End Property End Class

区别:

  • 经典的单例在第一次访问时创建实例,但需要手动同步。
  • “懒惰”版本使用.NET的内置机制在线程安全模式下创建实例。

陷阱问题。

这种代码实现单例有什么危险?

Public Shared ReadOnly Property Instance() As Singleton Get If _instance Is Nothing Then _instance = New Singleton() End If Return _instance End Get End Property

答案: 在多线程环境下,可能出现两个线程同时看到_instance为Nothing,并且都创建对象的情况。因此,这种方法并不是完全线程安全的。建议使用Lazy(Of T)SyncLock进行锁定。

因为不理解主题的细微之处而导致的实际错误示例。


故事

ERP系统: 在服务启动时,单例日志记录器有时会被创建两次,日志丢失。原因是属性中缺少同步,尽管应用程序是多线程的。


故事

Windows Forms应用程序: 项目中将与数据库的工作移到单例中,但未实现懒惰初始化。应用程序启动时发生了重负载连接,减慢了所有用户界面的加载。


故事

新闻平台插件: 尝试在模块中使用未保护的静态变量来实现单例,导致在高负载阶段出现多个电子邮件处理程序实例,造成邮件重复发送。