目录

单例模式定义:

单例模式核心原理:

使用单例模式需要注意哪几方面的问题:

饿汉单例

懒汉单例

DCL 单例(Double Check Lock)

静态内部类单例(推荐)

枚举单例

容器单例

最后

静态内部类时如何保证线程安全的:


单例模式定义:

1.确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。

单例模式核心原理:

1.将构造函数私有化;
2.通过静态方法获取唯一一个实例;

使用单例模式需要注意哪几方面的问题:

1.对象的资源消耗;
2.多余的同步;
3.线程安全;

饿汉单例

public class HungrySingletone {

    private static HungrySingletone instance = new HungrySingletone();

    private HungrySingletone() { }

    public static HungrySingletone getInstance() {
        return instance;
    }

}

优点:

缺点: 应用运行时,在非必要的情况下实例化,不节约内存空间

懒汉单例

public class LazySingletone {

    private static LazySingletone instance;

    private LazySingletone() { }

    /**
     * 获取实例时 初始化实例
     * @Description 考虑多线程并发调用getInstance,添加synchronized关键字
     * @return
     */
    public static synchronized LazySingletone getInstance() {
        if (instance == null) {
            instance = new LazySingletone();
        }
        return instance;
    }

    //每一次getInstance 都会被同步锁 开销, 并不是getInstance需要同步锁,
    //而是在new实例的时候需要同步锁
}

优缺点:

优点:相较于饿汉单例模式,在使用时才会实例化

缺点:多余的同步。为了保证多线程下单例对象唯一,getInstance()添加 synchronized 关键字,每次调用getInstance方法都会进行同步开销。

DCL 单例(Double Check Lock)

public class DclSingletone {

    private static DclSingletone instance;

    private DclSingletone() { }

    /**
     * 每一次getInstance
     *
     * @return
     * @Description 两重判断,做到单例模式的极致
     */
    public static DclSingletone getInstance() {
        //已经实例过,不需要同步锁
        if (instance == null) {
            synchronized (DclSingletone.class) {
                //第一次 多线程排队,初始实例  还是要在内部判空 是否new
                if (instance == null) {
                    instance = new DclSingletone();
                }
            }
        }
        return instance;
    }
}

优点:使用时实例化,线程安全,没有多余的同步

缺点:(在并发场景比较复杂,或者低于 JDK6 版本下使用,Dcl可能会失效,这个场景还不太懂 )

静态内部类单例(推荐)

public class StaticInnerSingletone {

    private StaticInnerSingletone() { }

    private static class InnerSingletoneHolder {
        private static final StaticInnerSingletone instance = new StaticInnerSingletone();
    }

    public static StaticInnerSingletone getInstance() {
        return InnerSingletoneHolder.instance;
    }

    //只有在第一次调用getInstance 才会初始化instance 不仅能够保证线程安全,也能保证单例对象的唯一性,同时也延迟了
    //单例对象的实例化,所以这是推荐使用的单例模式实现方式。

}

优点:使用时实例化,线程安全,没有多余的同步

缺点:

枚举单例

public enum SingletomeEnum {
    INSTANCE;
    //public method...
}

优点:写法简单..

缺点:(enum是不是占用内存多啊...)

容器单例

public class SingletoneManager {
    
    private static Map<String,Object> objMap = new HashMap<String,Object>();
    
    private SingletoneManager() { }
    
    public static void registerService(){
        
    }
    
    public static Object getService(String key){
        
    }
}

优点:多种单例类型注入到一个单例管理类,降低使用成本,并隐藏具体实现,降低耦合度。(系统 context 的 getSystemService() 使用容器单例)

缺点:看初始消耗的内存值不值得...

最后

静态内部类时如何保证线程安全的:

静态内部类的特点:外部类加载时不需要加载静态内部类,不被加载则不占用内存,(延迟加载)当外部类调用getInstance方法时,才加载静态内部类,静态属性保证了全局唯一,静态变量初始化保证了线程安全,所以这里的方法没有加synchronized关键字(JVM保证了一个类的 初始化在多线程下被同步加锁)