单例模式
-
懒汉式
在真正使用时才实例化
package com.ziwu.learn.designpattern.singleton; public class LazySingleTest { public static void main(String[] args) { //多线程 new Thread(()->{ LazySingle instanceT1 = LazySingle.getInstance(); System.out.println(instanceT1); }).start(); new Thread(()->{ LazySingle instanceT2 = LazySingle.getInstance(); System.out.println(instanceT2); }).start(); } } class LazySingle{ private volatile static LazySingle instance; private LazySingle(){ } public static LazySingle getInstance(){ if(instance==null){ synchronized (LazySingle.class){ //线程安全问题 //double check if(instance == null){ instance = new LazySingle();//new不是原子的:分配空间,初始化,引用赋值 //字节码层会有指令重排,赋值和初始化可以并行,会有空指针的问题 } } } return instance; } }
-
饿汉式
方式1:
package com.ziwu.learn.designpattern.singleton; public class HungrySingleTest { public static void main(String[] args) { HungrySingle instance = HungrySingle.getInstance(); HungrySingle instance1 = HungrySingle.getInstance(); System.out.println(instance.equals(instance1)); } } class HungrySingle{ private static HungrySingle instance = new HungrySingle(); private HungrySingle(){ } public static HungrySingle getInstance(){ return instance; } }
方式2:
package com.ziwu.learn.designpattern.singleton; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; public class InnerClassSingleTest { public static void main(String[] args) throws IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException { InnerClassSingle instance = InnerClassSingle.getInstance(); InnerClassSingle instance1 = InnerClassSingle.getInstance(); System.out.println(instance.equals(instance1)); //反射创建,可以打破单例的创建,但在有反序列化需求时,可能反序列化会有多个实例产生的情况 Constructor<InnerClassSingle> declaredConstructor = InnerClassSingle.class.getDeclaredConstructor(); declaredConstructor.setAccessible(true); InnerClassSingle innerClassSingle = declaredConstructor.newInstance(); System.out.println(instance1.equals(innerClassSingle)); } } class InnerClassSingle implements Serializable{ private static final long serialVersionUID = 001L; private InnerClassSingle(){ if(InnerClassHolder.instance!=null){ throw new IllegalArgumentException("单利不允许创建多个实例"); } } private static class InnerClassHolder{ private static InnerClassSingle instance = new InnerClassSingle(); } //解决反序列化出多个实例的问题,实现该方法即可,可以看Serializable接口对该方法的描述 Object readResolve() throws ObjectStreamException{ return InnerClassHolder.instance; } public static InnerClassSingle getInstance(){ return InnerClassHolder.instance; }
}
方式3:
使用枚举类创建单利可以防止反射创建出多个实例的问题,也可以防止反序列化出多个实例
package com.ziwu.learn.designpattern.singleton;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class EnumSingleTest {
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
EnumSingle instance = EnumSingle.INSTANCE;
EnumSingle instance1 = EnumSingle.INSTANCE;
System.out.println(instance.equals(instance1));
//runtime error Cannot reflectively create enum objects
//Constructor<EnumSingle> declaredConstructor = EnumSingle.class.getDeclaredConstructor(String.class,int.class);
//declaredConstructor.setAccessible(true);
//declaredConstructor.newInstance("INSTANCE",0);
//反序列化
//ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("Serial"));
//outputStream.writeObject(instance);
//outputStream.close();
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("Serial"));
EnumSingle enumSingle = (EnumSingle) objectInputStream.readObject();
System.out.println(enumSingle.equals(instance));//true
}
}
enum EnumSingle{
INSTANCE;
}
本质上是 利用类的加载机制来完成实例化