设计模式:单例设计模式

单例设计模式

由于某些类创建对象可能会耗费内存和花费时间。一般将这种类设计为单例设计模式会比较好。

1.对象在内存中只有一个,减少了内存的开销

2.可以控制对象的创建时刻

单例模式的特点:

1.单例的类在整个JVM中只有一个实例

2.需要提供一个全局访问点(1.公开的静态变量,2.公开的静态方法)

1.饿汉式:

特点:类加载的时候就创建了实例

//饿汉式
/*
 *1.类能被创建且只有一个实例
 * 2.提供一个全局的访问点
 * */
public class Singleton {
    //创建唯一的实例对象
    private static Singleton singletonInstance = new Singleton();
    //修改默认的构造器为私有的,屏蔽外部的new方法
    private Singleton() {}
    //全局的访问点
    public static Singleton getInstance() {
        return singletonInstance;
    }
}

2.懒汉式

特点:在需要创建实例的时候才调用方法创建实例对象

class Singleton2 {
    //保存唯一的实例对象
    private static Singleton2 singletonInstance;
    //修改默认的构造器为私有的,屏蔽外部的new方法
    private Singleton2() {}
    //全局的访问点
    public static Singleton2 getInstance() {
        if(singletonInstance == null) {
            singletonInstance = new Singleton2();
        }
        return singletonInstance;
    }
}

3.加锁的懒汉式

由于一般懒汉式不能保证线程安全。所以需要在方法加锁保证线程安全

//加锁的懒汉式
class Singleton3 {
    //保存唯一的实例对象
    private static Singleton3 singletonInstance;
    //修改默认的构造器为私有的,屏蔽外部的new方法
    private Singleton3() {}
    //全局的访问点
    //给创建实例的方法加锁。防止在多线程条件下线程问题
    public synchronized static Singleton3 getInstance() {
        if(singletonInstance == null) {
            singletonInstance = new Singleton3();
        }
        return singletonInstance;
    }
}

4.双重验证的懒汉式

由于枷锁的懒汉式对整个方法加了锁,会导致每次调用创建实例方法都会需要进行等待,但是如果实例已经创建了,应该是不想继续等待的。所以应该只在判断实例是否创建的地方加锁即可

class Singleton4 {
    //保存唯一的实例对象
    private static Singleton4 singletonInstance;
    //修改默认的构造器为私有的,屏蔽外部的new方法
    private Singleton4() {}
    //全局的访问点
    public  static Singleton4 getInstance() {
        if(singletonInstance == null) {
            //获取单例类的锁
            synchronized (Singleton4.class) {
                if(singletonInstance == null) {
                    singletonInstance = new Singleton4();
                }
            }
        }
        return singletonInstance;
    }
}

5.加上volatile关键字防止重排序的双重验证懒汉式

创建一个对象可以分为3步:

《设计模式:单例设计模式》

虽然重排序不会影响单线程的执行结果,但是由于判断的条件是instance == null,当分配了内存以后,其他线程来到判断的地方,instance不为空,所以直接将引用指向实例对象。但是实例对象还没有初始化,就会出现问题。

 所以需要放防止重排序

class Singleton5 {
    //volatile防止重排序
    private volatile static Singleton5 singletonInstance;
    //修改默认的构造器为私有的,屏蔽外部的new方法
    private Singleton5() {}
    //全局的访问点
    //给创建实例的方法加锁。防止在多线程条件下线程问题
    public  static Singleton5 getInstance() {
        if(singletonInstance == null) {
            //获取单例类的锁
            synchronized (Singleton5.class) {
                if(singletonInstance == null) {
                    singletonInstance = new Singleton5();
                }
            }
        }
        return singletonInstance;
    }
}

6.静态内部类的方式:通过类加载过程的线程安全来保证创建单例实例的线程安全

class Singleton6 {
    //修改默认的构造器为私有的,屏蔽外部的new方法
    private Singleton6() {}
    //静态内部类保存唯一的实例对象
    private static class InnerInstanceHolder{
        private static Singleton6 singletonInstance = new Singleton6();
    }
    //类加载是线程安全的,所以使用内部类持有唯一实例是线程安全的,且效率比较高
    public static Singleton6 getInstance() {
        return InnerInstanceHolder.singletonInstance;
    }
}

7.枚举方式

//枚举方式
public enum Singleton {
        INSTANCE;
        public void method() {
        }
}

暂时还没想懂枚举方式的特点。列出参考网站下次研究:

为什么我墙裂建议大家使用枚举来实现单例

 

图片参考来源:https://blog.csdn.net/qq_36109365/article/details/78090096

    原文作者:发包哥哥
    原文地址: https://www.cnblogs.com/fabaogege/p/10317632.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞