线程安全的单实例模式
我们都很清楚一个简单的单例模式该怎样去实现:构造函数声明为private或protect防止被外部函数实例化,内部保存一个private static的类指针保存唯一的实例,实例的动作由一个public的类方法代劳,该方法也返回单例类唯一的实例。单例大约有两种实现方法:懒汉与饿汉。
懒汉:故名思义,不到万不得已就不会去实例化类,也就是说在第一次用到类实例的时候才会去实例化,节省内存。
饿汉:饿了肯定要饥不择食。所以在单例类定义的时候就进行实例化。浪费内存
特点与选择:
由于要进行线程同步,所以在访问量比较大,或者可能访问的线程比较多时,采用饿汉实现,可以实现更好的性能。这是以空间换时间。
在访问量较小时,采用懒汉实现。这是以时间换空间。
一般在单例模式下使用.getInstance()创建对象;但并不是所有有私有构造方法,对外通过getInstance方法提供
判断Singelton一个类是否是单例模式: class Test{ public static void main(String args[]) { Singleton s1=Singleton.getInstance(); Singleton s2=Singleton.getInstance(); if(s1==s2) System.out.println("此类是单例模式"); else System.out.println("此类不是单例模式"); } }
首先是饿汉模式:
public class Singleton { private static Singleton instance = new Singleton();//类的静态对象 private Singleton (){} public static Singleton getInstance() { return instance; } }
懒汉模式:
描述:这种方式具备很好的 lazy loading,能够在多线程中很好的工作,但是,效率很低,99% 情况下不需要同步。 优点:第一次调用才初始化,避免内存浪费。 缺点:必须加锁 synchronized 才能保证单例,但加锁会影响效率。 getInstance() 的性能对应用程序不是很关键(该方法使用不太频繁)。 public class Singleton { private static Singleton instance;//类的静态对象(这里只是对类的静态对象做一个声明还未定义,类的静态对象需要定义后才可以使用) private Singleton (){} public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); //如果判断到类的静态对象还未构造就调用构造函数 } return instance; //如果判断类的静态对象已经构造好了就直接返回静态对象 } }
懒汉模式的另一种实现(不需要加锁):我们在内部定义了一个私有类型Nested。当第一次用到这个嵌套类型的时候,会调用静态构造函数创建Singleton的实例instance。类型Nested只在属性Singleton.Instance中被用到。由于其私有属性,他人无法使用Nested类型。因此,当我们第一次视图通过属性Singleton.Instance得到Singleton的实例时,会自动调用Nested的静态构造函数创建实例instance。如果我们不调用属性Singleton.Instance,就不会触发.NET运行时调用Nested,也不会创建实例,这样就真正做到了按需创建。
public class Singleton { Singleton(){} public static Singleton Instance() { return Nested.instance; } class Nested { static Nested(){}//静态构造函数(只能调用一次静态构造函数) internal static readonly Singleton instance =new Singleton();//因为静态构造函数只能被调用一次,所以每次创建返回的都是同一个对象 } }