单例模式自我心得
1、创建单例模式的几种方法
饿汉模式:也是思维上最常见的方式,我创建好了一个单例,无论何时来调用,都是可以的,反正我已经在这里了,无论你用或者不用,我都已经创建好了。
public class SingletonEHan{
//私有化构造方法
private SingletonEHan(){}
//类初始化时立即加载这个对象
private static SingletonEHan instance = new SingletonEHan();
//提供获取对象的方法,没有synchronize方法
public static SingletonEHan getInstance(){
return instance;
}
}
懒汉模式:我很懒,我不会一开始有把事情做好,只有到马上要用的时候我才回去创建单例。
public class SingletonLanHan{
//懒汉模式(调用的时候才开始加载,也就是new的时机)
private SingletonLanHan(){
}
private static SingletonDemo2 instance;
//因为此时可能多线程同时来创建单例,所以用synchronized关键字
public static synchronized SingletonLanHan getInstance(){
if(instance==null){
instance = new SingletonLanHan();
}
return instance;
}
}
DCL懒汉模式:正常的懒汉模式效率比较低,应为synchronized关键字放在了方法上边,所以当并发调用时,除了第一个进入方法,其余的都在等待状态,这样比较耗费时间。但是把synchronized关键字加在代码块上,再做一次双重验证就可以大大提升效率。
public class SingletonDCLLanHan{
//私有化构造方法
private SingletonDCLLanHan(){}
private static SingletonDCLLanHan instance;
public static SingletonDCLLanHan getInstance() {
//如果单例已经存在,则跳过if块,直接返回;如果单例为空,则创建单例对象
if(instance==null){
//创建过程代码块也是synchronize同步的
synchronized (SingletonDCLLanHan.class){
if(instance==null){
instance= new SingletonDCLLanHan();
}
}
}
return instance;
}
}
静态内部类:具体实现如下
public class SingletonInnerClass {
private SingletonInnerClass(){}
private static class InnerClass{
private static SingletonInnerClass instance= new SingletonInnerClass();
}
public static SingletonInnerClass getInstance(){
return InnerClass.instance;
}
}
2、之前四种实现方式是因为私有化构造方法,但是反射可以破坏私有,就是通过反射方式构造的对象,可以访问私有变量。代码如下:
public class Reflect{
//通过反射的getDeclaredConstructor方法
Constructor<SingletonDemo> constructor= SingletonDemo.class.getDeclaredConstructor(null);
constructor.setAccessible(true);
//反射方式获取类的对象
SingletonDemo singletonDemo = constructor.newInstance();
}
3、可以用枚举方法防止反射会破坏单例,也可以用如下方法一定程度上防止反射:
//在构造方法中防止反射
//第一次flag=false,然后设置为true,第二次再来调用构造方法时,会抛出异常
private static boolean flag = false;
private SingletonDemo2 (){
synchronized (SingletonDemo2.class){
if(flag==false){
flag = true;
} else{
throw new RuntimeException("不要试图用反射破坏单例模式");
}
}
}