23种设计模式——单例模式
一、实现方式
1、懒汉模式
class LazySingleton{
private static volatile LazySingleton instance;//volatile关键字防止指令重排序
private LazySingleton(){};//构造方法私有化,防止new对象
public static LazySingleton getInstance(){
if(null==instance){
synchronized (LazySingleton.class){
if(null==instance){
instance=new LazySingleton();
}
}
}
return instance;
}
}
2、饿汉模式
只有在主动使用对应的类时,才会触发初始化,如(当前类时启动类即main函数所在类,直接new操作,访问静态属性、访问静态方法的子类等)
class HungrySingleton{
private static HungrySingleton instance=new HungrySingleton();//初始化的时候是线程安全的
private HungrySingleton(){};
public static HungrySingleton getInstance(){
return instance;
}
}
3、静态内部类
当调用getInstance时才会进行类的初始化
class InnerClassSingleton{
private static class SingletonHolder{
private static InnerClassSingleton instance=new InnerClassSingleton();
}
private InnerClassSingleton(){};
public static InnerClassSingleton getInstance(){
return SingletonHolder.instance;
}
}
1)补充
用以上方式实现单例,当利用反射来创建对象时,获得的是并不是同一个实例,如下(以饿汉模式为例)
public class SingletonTest {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
Constructor<HungrySingleton> declaredConstructor = HungrySingleton.class.getDeclaredConstructor();
declaredConstructor.setAccessible(true);
HungrySingleton hungrySingleton = declaredConstructor.newInstance();
HungrySingleton instance=HungrySingleton.getInstance();
System.out.println(instance==hungrySingleton);
}
}
输出如下
输出false,得以证明通过反射获得的不是同一个实例
2)规避方式
在构造函数处加一个判断,不为空时则抛出异常
private HungrySingleton(){
if(instance!=null){
throw new RuntimeException("单例不允许多个实例");
}
};
如下:
4 、枚举方式
当使用枚举类型时,则不能使用反射创建实例,也可以规避上面问题,实现如下:
enum EnumSingleton{
INSTANCE;
}
public class SingletonTest {
public static void main(String[] args) {
EnumSingleton instance1 = EnumSingleton.INSTANCE;
EnumSingleton instance2 = EnumSingleton.INSTANCE;
System.out.println(instance1==instance2);
}
}
输出如下:
未完待续…