流殃

单例模式

发布于

了解一下

核心作用

保证一个类只有一个实例,并且提供一个访问该实例的全局访问点

常见的五种单例模式的是实现方式

  • 饿汉式(线程安全,调用效率高,不能延时加载)
  • 懒汉式(线程安全,调用效率不高,可以延时加载)
  • DCL懒汉式(由于JVM底层内部模型原因,偶尔会出现问题,不推荐使用)
  • 饿汉式改进(静态内部类,线程安全,调用效率高,可以延时加载)
  • 枚举单例(线程安全,调用效率高,不能延时加载)

饿汉式

//饿汉式单例模式
public class demo1 {
    //1. 私有化构造器
    private demo1(){
    }
//    2. 类初始化的时候,立即加载该对象;由于用了static关键字,在类装载的时候就初始化对象,
//    不存在并发问题,因为一加载就出来了
    private static demo1 instance=new demo1();
    //3. 提供获取该对象的方法;由于不存在并发问题,所以没有加synchronized关键字,效率高;如果考虑到并发情况,是要加synchronized关键字的;
    public static  demo1 getInstance(){
        return instance;
    }
}
//问题:如果在这个类中,加了一些开辟空间的方法,那么不管我用不用这个类,这个块空间都被占用了,
//浪费了资源,理想情况应该是在调用getInstance方法的时候,再去开辟空间;
class demo1Test{
    public static void main(String[] args) {
        demo1 instance=demo1.getInstance();
        demo1 instance1=demo1.getInstance();
        System.out.println(instance==instance1);
    }
}

懒汉式

public class demo2 {
    //1. 私有化构造器
    private demo2(){
    }
    //2. 类初始化的时候,不立即加载该对象
    private static demo2 instance;
    //3. 提供获取该对象的方法,由于可能会出现有多个线程来进来的话,需要让他们排队,否则都有问题
    // 所以有synchronized同步这个关键字,效率低!
    public static synchronized demo2 getInstance(){
        if(instance==null)
        {
            instance=new demo2();
        }
        return instance;
    }
}
class demo2Test{
    public static void main(String[] args) {
        demo2 instance=demo2.getInstance();
        demo2 instance1=demo2.getInstance();
        System.out.println(instance==instance1);
    }
}

DCL懒汉式

//DCL懒汉式
public class demo3 {
    private demo3(){
    }
    //2. 类初始化的时候,不立即加载该对象
    private volatile static demo3 instance;
    //volatile是后来加的
    //3. 提供获取该对象的方法,由于可能会出现有多个线程来进来的话,需要让他们排队,否则都有问题
    // 所以有synchronized同步这个关键字,效率低!
    //不用synchronized可以用synchronized代码块,锁demo3这个类本身;双重检测
    //分析:现在不需要对整个方法进行同步了,将锁的范围变得更精细了,如果有个进程进来了,发现
    //这个instance对象没有被创建,有一个锁,他首先要和其他进程竞争本类的锁,获得锁之后,再次检查,
    //如果还是null,说明他是第一个竞争到这个锁的,于是他这个线程就负责创建这个对象,其他的线程
    //进来之后,直接调用即可
    public static  demo3 getInstance(){
        if(instance==null)
        {
            synchronized (demo3.class){
                if(instance==null)
                {
                    instance=new demo3();
                }
            }
        }
        return instance;
    }
}
//由于这个操作不是原子性操作,所以他会经过下面几个步骤
//1.分配内存
//2. 执行构造方法
//3. 执行地址
//可能会出现的问题:极端情况,一个线程进来了,走到instance=new demo3(),还没有出去方法,
//结果另一个线程进来了,就会直接走到 return instance;,这样instance就是一个新的对象,
//破环了单例模式,可能会发生一些意想不到的问题;在这种情况下加volatile关键字;
//volatile可以保证一个线程在对这个变量进行修改的时候,另一个线程,该变量的缓存就失效了,直接读内存中的值
class demo3Test{
    public static void main(String[] args) {
        demo3 instance=demo3.getInstance();
        demo3 instance1=demo3.getInstance();
        System.out.println(instance==instance1);
    }
}

静态内部类实现

//静态内部类实现
public class demo4 {
    private demo4(){
    }
    private static class InnerClass{
        private static final demo4 instance=new demo4();
    }
    public static demo4 getInstance(){
        return InnerClass.instance;
    }
}
//反射机制可以破坏private
class demo4Test{
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        demo4 instance=demo4.getInstance();
        //通过反射拿到instance
        Constructor<demo4> demo4Constructor=demo4.class.getDeclaredConstructor(null);
        demo4Constructor.setAccessible(true);
        demo4 instance1=demo4Constructor.newInstance();
        System.out.println(instance==instance1);
        System.out.println(instance.hashCode());
        System.out.println(instance1.hashCode());
    }
}

优化静态内部类

public class demo5 {
    private demo5(){
        synchronized (demo5.class){
            if(instance!=null)
            {
                throw new RuntimeException("不要试图用反射破坏单例模式!");
            }
        }
    }
    //2. 类初始化的时候,不立即加载该对象
    private volatile static demo5 instance;
    public static  demo5 getInstance(){
        if(instance==null)
        {
            synchronized (demo5.class){
                if(instance==null)
                {
                    instance=new demo5();
                }
            }
        }
        return instance;
    }
}
class demo5Test{
    public static void main(String[] args) throws Exception {
        demo5 instance=demo5.getInstance();
        //通过反射拿到instance
        Constructor<demo5> demo4Constructor=demo5.class.getDeclaredConstructor(null);
        demo4Constructor.setAccessible(true);
        demo5 instance1=demo4Constructor.newInstance();
        System.out.println(instance==instance1);
        System.out.println(instance.hashCode());
        System.out.println(instance1.hashCode());
    }
}

枚举

//枚举
//反射不能够破坏枚举
public enum demo6 {
    INTERFACE;
    public demo6 getInstance(){
        return INTERFACE;
    }
}
class demo6Test{
    public static void main(String[] args) {
        demo6 anInterface = demo6.INTERFACE;
        demo6 anInterface2 = demo6.INTERFACE;
        System.out.println(anInterface==anInterface2);
    }
}