欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程语言 > asp.net >内容正文

asp.net

设计模式03------单例模式

发布时间:2025/7/25 asp.net 121 豆豆
生活随笔 收集整理的这篇文章主要介绍了 设计模式03------单例模式 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

参考文献:《Java与模式》

作为对象的创建模式,单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类。

一. 单例模式的要点

显然单例模式的要点有3个:

  • 某个类只能有一个实例
  • 它必须自行创建这个实例
  • 它必须自行向整个系统提供这个实例

二. 单例模式分类

1. 饿汉式单例类

它是在Java语言里实现起来最为简便的单例类。

public class EagerSingleton {private static final EagerSingleton instance=new EagerSingleton();/*** 私有的默认构造器*/private EagerSingleton() {}/*** 静态工厂方法*/public static EagerSingleton getInstance() {return instance;}}

说明:这个类被加载时,静态变量instance会被初始化,此时类的私有构造器会被调用。这个时候,单例类的唯一实例就被创建出来了。

因为构造器是私有的,因此该类是不可以被继承的。

2. 懒汉式单例类

与饿汉式单例类不同的是,懒汉式在第一次被引用时将自己实例化。如果加载器是静态的,那么在懒汉式类被加载时不会将自己实例化。

public class LazySingleton {private static LazySingleton instance=null;/*** 私有构造器*/private LazySingleton() {}/*** 静态工厂方法,返回此类的唯一实例*/synchronized public static LazySingleton getInstance() {if(instance==null) {instance=new LazySingleton();}return instance;}}

说明:在上面给出的懒汉式单例类中对静态工厂使用了同步化,以处理多线程环境。有些设计师在这里建议使用所谓的”双重检查成例“。必须指出的是,”双重检查成例“不可以在Java语言中使用。

饿汉式相比懒汉式,它的资源利用效率差一些,但是速度和反应时间上却很快。懒汉式在实例化时,必须处理好在多个线程同时首次引用此类时的访问限制问题,特别时当单例类作为资源控制器在实例化时必然涉及资源初始化,而资源初始化很可能耗费时间。这意味着出现多线程同时首次引用此类的几率变得较大。

3.登记式单例类

这个类是为了克服前两种不可以被继承的缺点而设计的。

public class RegSingleton {static private HashMap registry=new HashMap();static {RegSingleton instance=new RegSingleton();registry.put(instance.getClass().getName(), instance);}/*** 保护的默认构造器*/protected RegSingleton() {}/*** 静态工厂方法,返回此类的唯一的实例*/public static RegSingleton getInstance(String name) {if(name==null) {//key is nullname="com.test.b.RegSingleton";}if(registry.get(name)==null) {//value is nulltry {registry.put(name, Class.forName(name).newInstance());//利用的反射机制,创造一个单利对象加入registry}catch (Exception e) {System.out.println("Error happend");}}return (RegSingleton) registry.get(name);}/*** 一个示意性的商业方法*/public String about() {return "Hello, I am RegSingleton";}}

它的子类RegSingletonChild需要父类的帮助才能实例化。

public class RegSingletonChild extends RegSingleton{public RegSingletonChild() {}/*** 静态工厂方法*/public static RegSingletonChild getInstance() {return (RegSingletonChild) RegSingleton.getInstance("com.test.b.RegSingletonChild");}/*** 一个示意性的商业方法*/public String about() {return "Hello, I am RegSingletonChild";} }

缺点:父类的实例必须存在才可能有子类的实例

三. 双重检查成例的研究

双重检查成例(Double Check Idiom)是从C语言移植过来的一种代码模式。具体分析如下:

1. 未使用任何线程安全考虑的错误例子

首先考虑一个单线程的版本,代码如下:

public class Foo {private Helper helper=null;public Helper getHelper() {if(helper==null) {helper=new Helper();}return helper;} }

说明:这是一个错误的例子。写出这样的代码,本意显然是要保证在整个JVM中只有一个Helper的实例。因此,才会有if(helper==null)的检查。非常明显的是,如果在多线程的环境中运行,上面的代码会有两个甚至两个以上的helper对象被创建出来,从而造成错误。想象一下在多线程中的情况。假设两个线程A和B几乎同时到达if(helper==null)语句的外面,假设A稍微比B早一点点,则:

2. 线程安全的版本

public class Foo {private Helper helper=null;public synchronized Helper getHelper() {if(helper==null) {helper=new Helper();}return helper;} }

3. 画蛇添足的”双重检查“

仔细审查上面的正确答案会发现,同步化实际上只是在helper变量第一次被赋值之前才有用。在helper变量有了值以后,同步化实际上变成了一个不必要的瓶颈。如果有一个方法减去这个小小的额外开销,不是更加完美吗?所以”双重检查“来了,它是反面教材,在Java编译器里面无法实现。

public class Foo {private Helper helper=null;public Helper getHelper() {if(helper==null) {//第一次检查(位置1)//这里会有多余一个的线程同时到达(位置2)synchronized (this) {//这里在每个时刻只能有一个线程(位置3)if(helper==null) {//第二次检查(位置4)helper=new Helper();}} }return helper;} }

这是错误的例子:因为Java编译器并不支持这种双重机制。为什么呢?

不能工作的根本原因在于,在Java编译器中,LazySingleton类的初始化与m_instance变量赋值的顺序不可预料。如果一个线程在没有同步化的条件下读取m_instance引用,并调用这个对象的方法的话,可能会发现对象的初始化过程尚未完成,从而造成崩溃。因此,双重检查成立对Java语言来说是不成立的。

 

转载于:https://www.cnblogs.com/Hermioner/p/10014136.html

总结

以上是生活随笔为你收集整理的设计模式03------单例模式的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。