之前面试百度的时候,面试官问我:“单例模式需要注意的点是什么?”,当时感觉答得有点乱,
经过之后的学习总结下来应该注意以下两点:
public class Singleton {
private static Singleton INSTANCE;
// 构造方法一定要用private修饰!
private Singleton() {
}
public static Singleton getSingleton() {
// 懒加载实现
if (INSTANCE == null) {
INSTANCE = new Singleton();
}
return INSTANCE;
}
}
存在问题:
dcl —> duplication check lock
public class Singleton {
private volatile static Singleton INSTANCE;
// 构造方法一定要用private修饰!
private Singleton() {
}
public static Singleton getSingleton() {
if (INSTANCE == null) {
synchronized(Singleton.class){
if (INSTANCE == null) {
INSTANCE = new Singleton();
}
}
}
return INSTANCE;
}
}
解释:
防止指令重排,获取到半个对象
防止特殊情况:俩对象同时进入到
if (INSTANCE == null)
这个判断中
public class Singleton2 {
// 构造方法一定要用private修饰!
private Singleton2() {
}
private static class Singleton2Dummy {
private static final Singleton2 INSTANCE = new Singleton2();
}
public static Singleton2 getSingleton() {
return Singleton2Dummy.INSTANCE;
}
}
说明:
静态内部类是静态的,所以是类的一部分,加载当前类(Singleton2 )的时候也会加载这个内部类,并给他的值初始化,相当于已经实例化好了这个内部类,不管你调用与否,它都在这里生成了,且是独一份的!
缺点:
2. 非要说缺点那就是他不管用不用都被实例化了,会占用点内存!
《Effective Java》作者是约书亚·布洛克(Joshua Bloch)在书中提到单例模式最优解如下:
public enum Singleton3 {
INSTANCE;
public void 具体实现() {
}
public static void main(String[] args) {
IntStream.range(1, 100).forEach(num -> {
new Thread(() -> {
System.out.println(Singleton3.INSTANCE.hashCode());
}).start();
});
}
}
说明: