单例模式
- 饿汉式
public class SingleProto1 {
// 程序加载即会创建对象
private static SingleProto1 instance = new SingleProto1();
// 防止被别人创建对象
private SingleProto1(){
}
// 提供调用方获取对象的方法,保证拿到的是唯一的对象
public static SingleProto1 getInstance(){
return instance;
}
}
如果不需要用到这个对象时,对象仍会存在内存中,浪费空间,浪费资源,所以出现了下面的懒汉式,即需要对象时再进行创建
- 懒汉式
public class SingleProto2 {
private static SingleProto2 instance = null;
// 防止被别人创建对象
private SingleProto2(){
}
// 提供调用方获取对象的方法,保证拿到的是唯一的对象
public static SingleProto2 getInstance(){
if(instance == null){
return new SingleProto2();
}else {
return instance;
}
}
}
懒汉式使用时,如果出现多线程操作同一个对象,会出现线程安全问题,如图:
此时加上同步关键字即可:
这样的情况,又会有吹毛求疵的人会说:万一你创建对象之前有很多的逻辑代码需要处理该怎么办,此时锁需要进行细化,就仅仅需要在需要加锁的地方进行加锁,所以出现下面的代码:
此时仍然会出现线程安全问题,当两个线程先后进入到null条件时,一个线程创建完对象后,另一个线程也在null条件中,此时锁释放拿到锁也可以创建新的对象,就不能保证对象是单例的。
所以出现了DCL,即Double Check Lock
此时最值得注意的是,关乎多个线程操作单例单例对象时,需要在对象前加volatile关键字,保证线程间的可见性,并且避免指令的重排从而达到线程安全