• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

张秋天

  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

《设计模式》之单例模式

 

一、饿汉式

类加载时就初始化创建单例对象,线程安全

不管是否使用,都创建对象可能会浪费内存。

public class HungrySingleton {
   private HungrySinglenton(){}
    
    private static final HungrySingleton hs = new HungrySingleton();

    public static HungrySingleton getInstance(){
        return hs;
    }
}

 

二、懒汉式

在外部调用时才会加载,加锁保证线程安全,但效率低。

public class LazySingleton {

    private static volatile LazySingleton ls = null;

    private LazySingleton(){}

    public static synchronized LazySingleton getInstance(){
        if(ls == null){
            return new LazySingleton();
        }else{
            return ls;
        }
    }
}

 

***三、双重检查锁 

 

public class DCL { 

    private volatile static DCL instance; 
    private DCL(){}

    public static DCL getInstance() { 
        
        if (instance == null) { // 第一次检查
            // A、B
            synchronized (DCL.class) { 
                if (instance == null) // 第二次检查
                    instance = new DCL(); 
            } 
        }
        return instance; 
    } 

}

  

使用 volatile 以及多重检查 减小锁的范围

如果一次判断,去掉外层的 null 判断,每次获取单例 都需要加锁。

 

为什么两次判断

synchronized 保证创建过程 线程安全,避免多个线程同时创建多个单例对象。

 

第一次判断,验证是否创建对象
第二次判断,为了避免重复创建单例,存在多个线程通过了第一次判断在等待锁,来创建新的实例对象。

当A与B同时调用,判断第一个if都为空

1)A拿到锁,进行第二层 if 判断,条件成立new了一个对象;

2)B在外层等待,A创建完成,释放锁,B拿到锁,进行第二层if判断,条件不成立,结束释放锁。

 

volatile 作用 :对象引用的可见性、禁止指令重排序

 

volatile 保证 对象引用的可见性 和 禁止指令重排序。通过内存屏障禁止指令重排序

 

禁止指令重排序

instance = new Singleton() 

不是一个原子操作,有 3个步骤:

  1. 分配内存空间
  2. 实例化对象
  3. 对象引用赋值给 instance

 

没有 volatile ,可能会出现指令重排序

1)先将对象引用赋值给 instance,但对象实例化操作还没完成。

2)其他线程检查 instance == null,认为单例已经创建,得到一个未完全初始化的对象。

 

看见性

确保对 instance 的修改对所有线程可见

 

 

四、静态内部类

同时解决

饿汉式的内存浪费问题

懒汉式的线程安全问题

public class StaticSingleton {
    
    private StaticSingleton(){}

    public static StaticSingleton getInstance() {
        return StaticClass.instance;
    }

    private static class StaticClass {
        private static final StaticSingleton instance = new StaticSingleton();
    }
}

 

 

 

posted on 2021-01-24 21:24  张秋天  阅读(83)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3