目录
单例模式定义:
单例模式核心原理:
使用单例模式需要注意哪几方面的问题:
饿汉单例
懒汉单例
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保证了一个类的 初始化在多线程下被同步加锁)