zoukankan      html  css  js  c++  java
  • 单例模式-懒汉式(双重检验)

    上章节我们在懒汉式的单例模式上解决了多线程安全的问题,但解决问题的同时,新的问题也随之而来。

    上节问题:

    1、在静态方法(static)上添加关键字(synchronized同步锁),就是相当于在类上加锁,锁的范围大,损耗性能。

    2、加锁、解锁过程消耗资源。

    那么,我们该如何解决呢?

     1 public class lazyDoubleCheckSingleton {
     2 
     3   private static lazyDoubleCheckSingleton lazyDoubleCheckSingleton = null;
     4 
     5   private lazyDoubleCheckSingleton() {
     6 
     7   }
     8   public static lazyDoubleCheckSingleton getInstance() {
     9     if (lazyDoubleCheckSingleton == null) {
    10       synchronized (lazyDoubleCheckSingleton.class){
    11         if (lazyDoubleCheckSingleton == null){
    12           lazyDoubleCheckSingleton = new lazyDoubleCheckSingleton();
    //1、分配内存给这个对象
    //2、初始化对象
    //3、设置
    lazyDoubleCheckSingleton,指向刚分配的内存地址
    13  } 14  } 15  } 16 return lazyDoubleCheckSingleton; 17  } 18 }

    此种方法就是懒汉模式的双重检测式,把锁加在方法里面,只有空的话才会加锁,不为空的话,直接return lazyDoubleCheckSingleton,大大节省了开销,但是这段代码,还存在着两大隐患,分别是9行、12行,首先在9行判断了是否为空,有可能是不为空的,他虽然不为空,但是是在12行还没完成初始化的情况下,12行的代码虽然是一行,确实经历了三个步骤,注释上2和3的顺序可能调换,进行重排序,也就是先指向内存地址,但是还没初始化对象。下面给大家开一个图。

    这是单线程,介入多线程呢?

    看吧,就出问题了呢,想要解决这个问题,有两种解决方案

    1、不允许2、3进行重排序,加入了volatile关键字.
    2、允许一个线程进行重排序,但不允许另外线程看到他的重排序。
    那么我们看看用第一种方案是怎么解决的呢?
    /**
     * Created by sww_6 on 2019/4/10.
     * 双重检查
     * 1、不允许2、3进行重排序,加入了volatile关键字.
     * 2、允许一个线程进行重排序,但不允许另外线程看到他的重排序。
     * 划重点:
     * 1、在多线程的时候,cpu有共享内存。
     * 2、加入了volatile关键字之后,所有线程都能看到共享内存的最新状态,保证内存可见性。
     * <p>
     * 怎么保持内存一致性?
     * 用volatile修饰的共享变量,在进行写操作的时候,会多出来很多汇编代码,起到两个作用。
     * 1、是将当前处理器缓存行的数据写回到系统内存,写回内存的操作,会使在其他cpu里缓存了该内存的数据无效,其他cpu缓存的数据无效了,就会从共享内存同步数据。保证了内存的可见性。
     * 主要使用的是缓存一致性协议
     * <p>
     * 优点:
     * 既兼顾了性能,又兼顾了线程安全。
     */
    public class lazyDoubleCheckSingleton {
    
     private volatile static lazyDoubleCheckSingleton lazyDoubleCheckSingleton = null;
    private lazyDoubleCheckSingleton() {
    }
    public synchronized static lazyDoubleCheckSingleton getInstance() {
    if (lazyDoubleCheckSingleton == null) {
    synchronized (lazyDoubleCheckSingleton.class) {
    if (lazyDoubleCheckSingleton == null) {
    lazyDoubleCheckSingleton
    = new lazyDoubleCheckSingleton();
    }}}

    return lazyDoubleCheckSingleton;
    } }

    好了,我们下期见!

     
    想要飞得更高,就该忘记地平线!
  • 相关阅读:
    前端提示“页面正在载入”的功能实现
    JSON那些事
    如何让nodejs同步操作
    nodejs的一些局限
    《javascript高级程序设计》读书笔记——作用域
    svn教程
    从雷军谈小米中的一些思考
    云Vps安全设置
    不同服务器数据库之间的数据操作
    C#语言的Excel文件导入导出
  • 原文地址:https://www.cnblogs.com/shenwen/p/10686682.html
Copyright © 2011-2022 走看看