单例模式顾名思义,就是只能创建一个对象,这里就限制了它的构造方法,不能随便new了。所以用构造方法用private修饰。
饿汉式和懒汉式通过名字也是可以区分的。
饿汉式,饿了就主动去找食物了,就直接主动创建一个对象。然后通过公共的方法暴露给外部调用。
懒汉式,懒了就用的时候再去创建对象,所以原来设置个空的。需要用的时候,先检查有没有对象,如果没有,就调用公共的方法来new一个对象出来。下面是二者的代码。可以做一下对比。
饿汉式
public class Singleton {
private Singleton () {}
private static Singleton instance=new Signleton();
public static Singleton getInstance() {
return instance;
}
}
懒汉式
public class Singleton {
private Sigleton() {}
private static Singleton instance=null;
public static Singleton getInstance() {
if(instance==null) {
instance=new Singleton();
}
return instance;
}
}
二者的实质区别:
懒汉式是现成不安全的,因为假设Singleton类刚刚被初始化,instance对象还是空,这时候两个线程同时访问getInstance,可能就会new两次。就不是单例模式了。
修改代码如下。
public class Singleton {
private Singleton() {} //私有构造函数
private static Singleton instance = null; //单例对象
//静态工厂方法
public static Singleton getInstance() {
if (instance == null) { //双重检测机制
synchronized (Singleton.class){ //同步锁
if (instance == null) { //双重检测机制
instance = new Singleton();
}
}
}
return instance;
}
}
为了防止new Singleton被执行多次,因此在new操作之前加上Synchronized 同步锁,锁住整个类(注意,这里不能使用对象锁)。
进入Synchronized 临界区以后,还要再做一次判空。因为当两个线程同时访问的时候,线程A构建完对象,线程B也已经通过了最初的判空验证,不做第二次判空的话,线程B还是会再次构建instance对象。
以上其实也不是绝对的安全的。再修改可以用volatile关键字来修改,或者用枚举。这里自己学的不是很深,参考漫画吧。链接如下。https://zhuanlan.zhihu.com/p/33102022