单例模式适用在一个项目中只需要使用一个唯一的对象的情况下,这样可以保证项目中任何一个地方的修改在其他地方都可以接收到,从而保证数据的唯一性和共享性。
饿汉式代码
public class Hungry {
private static Hungry mHungry = new Hungry();
/**
* 构造方法私有可以避免调用者错误的创建新的对象
* 这还是很重要的
* */
private Hungry() {
}
/**
* 供调用者在外部使用使用
* */
public static Hungry getInstance() {
return mHungry;
}
从这段代码中可以看出当类在加载的时候就会实现对象的实例化,而不是在需要使用的才实例化,一上来就实现,是不是很像一个饿了几天的人见到事物的情形,饿汉式名称也由此得来。
优点:这种写法比较简单,就是在类加载加载的时候就完成了实例化,避免了多线程同步问题。
缺点:在类加载的时候就进行初始化,导致在程序刚开始运行的时候负荷比较集中,如果这个类从始至终都未使用过,则会造成内存的浪费。
懒汉式(饱汉式)
public class FullMode {
private static FullMode mFullMOde;
private FullMode(){}
public static FullMode getInstance(){
if(mFullMOde==null){
mFullMOde=new FullMode();
}
return mFullMOde;
}
}
从这段代码中可以看出,当类在加载的时候,并没有实现对象的实例化,而是在调用者第一次调用的时候实例化。在创建的过程中不像饿汉式那样一上来就创建,所以才有了这个相对饿汉式的名字:懒汉式或饱汉式。
优点:实现了在使用的时候才会实例化,项目中不使用时不会造成内存的浪费。
缺点:无法保证在多线程中使用的是同一个对象,有可能产生多个实例,所以多线程情况下应避免使用。
双重检验
public class DoubleMode {
private static DoubleMode mDoubleMode;
private DoubleMode() {
}
public static DoubleMode getInstance() {
if (mDoubleMode == null) {
synchronized (DoubleMode.class) {
if (mDoubleMode == null) {
mDoubleMode = new DoubleMode();
}
}
}
return mDoubleMode;
}
}
从这里可以看出,这里考虑到了线程安全的问题,在getInstance()这个方法中对对象是否为空进行了两次判断,所以这也就是双重检验名字的由来。
优点:线程安全,同时也实现了懒加载。
缺点:JDK小于1.5的时候不可用。
从这里可以看出,单例模式的共同点之一就是将构造方法私有化避免使用者自行创建;另外一个共同点就是因为构造方法的私有化,导致外界无法通过new来实例化对象,所以需要将外界使用的方法改为静态,否则这个方法在外界无法使用。
注:之前我看过有公众号上写出了单例模式的9种形式,包括对懒汉式和饿汉式的修改,增加同步判断或者使用静态代码块等。