单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中一个类只有一个实例,并提供一个全局访问点。
使用单例模式的目的在于尽可能节约内存空间,减少GC的消耗。
一个类能否成为单例,主要就是说这些类在应用中如果有两个以上实例会引起一定错误。
首先看下一个最原始的单例模式
public class Singleton {
//一个静态的实例
private static Singleton singleton;
//私有化构造函数
private Singleton(){}
//给出一个公共的静态方法返回一个单一实例
public static Singleton getInstance(){
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}
上面最原始的代码主要通过静态实例+私有化构造方法来创建的。但是如果考虑到多线程的话,上面的代码就不行了,那么有人想到用synchronize,
public class Singleton{
private static Singleton singleton=null;
private Singleton(){}
public synchronized static Singleton getInstance(){
if(singleton==null){
singleton=new Singleton();
}
return singleton;
}
}
做法是很简单,但是会造成很多无谓的等待,是非常不好的设计。其实,将上面的更改下就会好多了,如下:
public class Singleton{
private static Singleton singleton=null;
private Singleton(){}
public static Singleton getInstance(){
if(singleton == null){
synchronized (Singleton.class){
if(singleton == null){
singleton=new Singleton();
}
}
}
return singleton;
}
}
在只有实例为null的情况下才会去创建同步,大大减少了同步时间,而在同步内的if判断是因为,如果线程A和线程B都在synchronized外判断了singleton为null,然后A获取了线程锁然后将singleton实例化了,最后释放锁,这时,B拿到了锁,而如果没有在此判断singleton是否为nul的话,B就会在创建一个实例了。
虽然上面的已经基本解决了在多线程下的单例模式,但考虑其他方面,上述方式也存在一定局限。下面介绍最终两种方式:饿汉模式和懒汉模式
饿汉模式:系统中对象只有有一个唯一的实例,将对象的创建交给成员变量,空间换时间,一开始就创建实例。但容易造成资源的浪费,不过也没什么影响。
public class MyServlet {
private static MyServlet instance = new MyServlet();
private MyServlet(){}
public static MyServlet getInstance(){
return instance;
}
}
懒汉模式(推荐):用到实例时候再初始化对象,使用静态内部类实现可以避免多线程下的安全问题。
public class LazySingleton {
private static class Inner{
private static LazySingleton instance = new LazySingleton();
}
private LazySingleton(){}
public static LazySingleton getInstance(){
return Inner.instance;
}
}
下一节:命令模式