1双重锁懒汉模式(Double Check Lock)
public class SingleTon{ private static SingleTon INSTANCE = null; private SingleTon(){} public static SingleTon getInstance(){if(INSTANCE == null){ //避免非必要加锁 synchronized(SingleTon.class){ if(INSTANCE == null){ INSTANCE = new SingleTon(); } } return INSTANCE; } } }
分析:
new 一个对象 jVM 执行3步
INSTANCE = new SingleTon();
1.在堆内存开辟内存空间。
2.在堆内存中实例化SingleTon里面的各个参数。
3.把对象指向堆内存空间。
结论:以上存在安全问题
解决办法:INSTANCE 用voliate修饰 确保每次均在主内存中读取
心法口诀: 懒汉双重锁 莫忘voliate
2 静态内部类模式:
public class SingleTon{
private SingleTon(){}
private static class SingleTonHoler{
private static SingleTon INSTANCE = new SingleTon();
}
public static SingleTon getInstance(){
return SingleTonHoler.INSTANCE;
}
}
分析:
1外部类加载时并不需要立即加载内部类,则不去初始化INSTANCE,故而不占内存
2当SingleTon第一次被加载时,并不需要去加载SingleTonHoler,
只有第一次调用getInstance()时,才会去初始化INSTANCE,
第一次调用getInstance()方法会导致虚拟机加载SingleTonHoler类,
这种方法不仅能确保线程安全,也能保证单例的唯一性,同时也延迟了单例的实例化。
静态内部类也有着一个致命的缺点,就是传参的问题,由于是静态内部类的形式去创建单例的,故外部无法传递参数进去
心法口诀:懒汉懒不懒 要问累不累(内部类)
另外:
枚举在java中与普通类一样,都能拥有字段与方法,而且枚举实例创建是线程安全的