创建者模式->单例模式
单例模式
保证在一个JVM(虚拟机)中,该对象只有一个实例存在,可以存在多个对象,但是对象的本质相同
单例应该具备:
* 1线程的安全
* 2调用效率高
* 3懒加载
First 饿汉式实现 (线程安全,调用效率高,不能延时加载)
public class Demo1 { //构造方法私有 private Demo1() { } //饿汉式单例实现 提前实例化 private static final Demo1 A=new Demo1(); //* 静态工厂方式 public static Demo1 getInstance()// 相当于一个方法 { return A; } }
Second 懒汉式 (线程安全,调用效率低,可以延时加载)
public class Demo2 { private Demo2() { } /* *懒汉式单例实现 * 在第一次调用时实例化 * 需要使用线程同步,并发的效率低 * 实现了延时加载,用的时候加载 */ private static Demo2 A; public static synchronized Demo2 getInstance() //synchronized 线程同步,同一时刻,只有一个线程进入这个方法 { if(A==null) { //第一次调用的时候实例化 System.out.println("第一次调用的时候实例化"); A=new Demo2(); } return A; } }
Third 双重检测锁模式 (JVM底层问题,不建议使用)
/*由于编译器优化原因和JVM底层内部模型的原因,这个是最难用的,容易崩溃*/ public class Demo3 { private Demo3(){}; private static Demo3 A=null; public static Demo3 getInstance() { if(A==null) { Demo3 sc=null; synchronized (Demo3.class) { sc=A; if(sc==null) { synchronized (Demo3.class) { if(sc==null) { sc=new Demo3(); } } A=sc; } } } return A; } }
Fourth 静态内部类 (线程安全,调用效率高,可以延时加载)
//几乎就是最完美的方法 public class Demo4 { private static class SingClassinstance { private static final Demo4 Instance= new Demo4(); } public static Demo4 getInstance() { return SingClassinstance.Instance; } private Demo4(){}; }
Fifth 枚举 (线程安全 调用效率最高 不能延时加载 在底层上可以防止反射和反序列漏洞)
//枚举类 没有延时加载 //避免反射和反序列化的漏洞 //本身就是单例 public enum Demo5 { A; }
总结与一下效率问题
单纯在时间来看
饿汉式<静态内部类<枚举式<双重检测锁式<懒汉式
————————————————————- 下面的东西完全可以不看,除非开发底层的项目——————
Demo2P 防止反射
public class Demo2P { private Demo2P() { if (A!=null) { throw new RuntimeException("防止反射已开启"); } } private static Demo2P A; public static synchronized Demo2P getInstance() //synchronized 线程同步,同一时刻,只有一个线程进入这个方法 { if(A==null) { //第一次调用的时候实例化 System.out.println("第一次调用的时候实例化"); A=new Demo2P(); } return A; } }
Demo2S 防止反序列
public class Demo2S { private Demo2S() { } private static Demo2S A; public static synchronized Demo2S getInstance() //synchronized 线程同步,同一时刻,只有一个线程进入这个方法 { if(A==null) { //第一次调用的时候实例化 System.out.println("第一次调用的时候实例化"); A=new Demo2S(); } return A; } //反序列化时如果定义了如下方法,则直接返回指定的对象, 不需要单独的再创建对象 private Object readResolve () throws Exception { return A; } }
反射的方法破坏单例模式
public class Test_FanShe { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { Class<Demo2> clazz= (Class<Demo2>) Class.forName("设计模式.创建者模式.单例模式.Demo2"); Constructor<Demo2> c =clazz.getDeclaredConstructor(null); //跳过权限的检查 c.setAccessible(true); Demo2 S3= c.newInstance(); Demo2 S4=c.newInstance(); System.out.println(S3); System.out.println(S4); //现在可以被反射,导致单例模式失败 //Demo2P可以防止反射 Class<Demo2P> clazz2= (Class<Demo2P>) Class.forName("设计模式.创建者模式.单例模式.Demo2P"); Constructor<Demo2> c2 =clazz.getDeclaredConstructor(null); Demo2 S5= c2.newInstance(); Demo2 S6=c2.newInstance(); System.out.println(S5); System.out.println(S6); } }
反序列的方法破坏单例模式
public class Test_xuliehua { public static void main(String[] args) throws IOException, ClassNotFoundException { Demo2F S1=Demo2F.getInstance(); Demo2F S2=Demo2F.getInstance(); FileOutputStream fos= new FileOutputStream("fxlh.txt"); ObjectOutputStream oos= new ObjectOutputStream(fos); oos.writeObject(S1); fos.close(); oos.close(); // 取出 ObjectInputStream ois = new ObjectInputStream(new FileInputStream("fxlh.txt")); Demo2F S3=(Demo2F) ois.readObject(); System.out.println(S1); System.out.println(S2); System.out.println(S3); } }
版权声明:本文为Loving-Q原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。