单例模式 
  保证在一个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 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/Loving-Q/p/12782871.html