首页 > 其他分享 >单例模式的几种写法(包含双检锁写法)

单例模式的几种写法(包含双检锁写法)

时间:2023-04-28 11:00:48浏览次数:28  
标签:Singleton private instance static 双检锁 单例 线程 写法 public


饿汉式单例类



    1. public class
    2. {  
    3. private
    4.       
    5.     }  
    6.   
    7. private static Singleton instance = new
    8.   
    9. private static
    10. return
    11.     }  
    12. }



     饿汉式提前实例化,没有懒汉式中多线程问题,但不管我们是不是调用getInstance()都会存在一个实例在内存中

    内部类式单例类




    1. public class
    2. {        
    3. private
    4.          
    5.     }     
    6.     
    7. private class
    8. private static Singleton instance = new
    9.     }     
    10.     
    11. private static
    12. return
    13.     }     
    14. }



     

    内部类式中,实现了延迟加载,只有我们调用了getInstance(),才会创建唯一的实例到内存中.并且也解决了懒汉式中多线程的问题.解决的方式是利用了Classloader的特性.

     

    懒汉式单例类




    1. public class
    2. {        
    3. private
    4.     
    5.     }     
    6.     
    7. private static
    8. public static
    9. if(instance == null){     
    10. return instance = new
    11. else{     
    12. return
    13.         }     
    14.     }     
    15. }



     

    在懒汉式中,有线程A和B,当线程A运行到第8行时,跳到线程B,当B也运行到8行时,两个线程的instance都为空,这样就会生成两个实例。解决的办法是同步:

    可以同步但是效率不高:




    1. public class
    2. {        
    3. private
    4.     
    5.     }     
    6.     
    7. private static
    8. public static synchronized
    9. if(instance == null){     
    10. return instance = new
    11. else{     
    12. return
    13.         }     
    14.     }     
    15. }
    1.  



     

    这样写程序不会出错,因为整个getInstance是一个整体的"critical section",但就是效率很不好,因为我们的目的其实只是在第一个初始化instance的时候需要locking(加锁),而后面取用instance的时候,根本不需要线程同步。 
    于是聪明的人们想出了下面的做法:

    双检锁写法:




    1. public class
    2. private static Singleton single;    //声明静态的单例对象的变量
    3. private Singleton(){}    //私有构造方法 
    4.     
    5. public static Singleton getSingle(){    //外部通过此方法可以获取对象  
    6. if(single == null){     
    7. synchronized (Singleton.class) {   //保证了同一时间只能只能有一个对象访问此同步块      
    8. if(single == null){      
    9. new
    10.         }     
    11.       }  
    12.     }    
    13. return single;   //返回创建好的对象 
    14.   }  
    15. }



     

     

    思路很简单,就是我们只需要同步(synchronize)初始化instance的那部分代码从而使代码既正确又很有效率。 
    这就是所谓的“双检锁”机制(顾名思义)。 
    很可惜,这样的写法在很多平台和优化编译器上是错误的。 

    原因在于:instance = new Singleton()这行代码在不同编译器上的行为是无法预知的。一个优化编译器可以合法地如下实现instance = new Singleton(): 

    1. instance  = 给新的实体分配内存 

    2. 调用Singleton的构造函数来初始化instance的成员变量 

    现在想象一下有线程A和B在调用getInstance,线程A先进入,在执行到步骤1的时候被踢出了cpu。然后线程B进入,B看到的是instance  已经不是null了(内存已经分配),于是它开始放心地使用instance,但这个是错误的,因为在这一时刻,instance的成员变量还都是缺省值,A还没有来得及执行步骤2来完成instance的初始化。 

    当然编译器也可以这样实现: 

    1. temp = 分配内存 

    2. 调用temp的构造函数 

    3. instance = temp 

    如果编译器的行为是这样的话我们似乎就没有问题了,但事实却不是那么简单,因为我们无法知道某个编译器具体是怎么做的,因为在Java的memory model里对这个问题没有定义。 

    双检锁对于基础类型(比如int)适用。很显然吧,因为基础类型没有调用构造函数这一步。

    标签:Singleton,private,instance,static,双检锁,单例,线程,写法,public
    From: https://blog.51cto.com/u_16091571/6233590

    相关文章

    • Python单例的常用几种实现方法
      这两天在看自己之前写的代码,所以正好把用过的东西整理一下,单例模式,在日常的代码工作中也是经常被用到,所以这里把之前用过的不同方式实现的单例方式整理一下。装饰器的方式这种方式也是工作中经常用的一种,用起来也比较方便,代码实现如下defSingleton(cls):_instance={......
    • 单例模式
      一、线程安全性的讲解1、视频截图 2、线程安全性的代码加不加临界区进行验证1//!!!!!!!!!加C++泛型编程与STL开发实战QQ群:726114806下载代码和交流2#include<afxwin.h>3#include<iostream>4#include<stdio.h>5usingnamespacestd;67CRITICAL_SECTIONg_......
    • Vue3路由正确写法
      import{createRouter,createWebHistory}from'vue-router'importHomefrom'@/view/Home.vue';importLoginfrom'@/view/Login.vue'constroutes=[{path:'/',component:Home},{path:'/login',......
    • 【单例设计模式原理详解】Java/JS/Go/Python/TS不同语言实现
      简介单例模式(SingletonPattern)属于创建型设计模式,这种模式只创建一个单一的类,保证一个类只有一个实例,并提供一个访问该实例的全局节点。当您想控制实例数目,节省系统资源,并不想混用的时候,可以使用单例模式。单例有很多种实现方式,主要分为懒汉和饿汉模式,同时要通过加锁来避免线程......
    • 单例核心点
      1.构造方法是私有的private2.单例方法getInstance是public的保证对外能公开访问3.单例的方法getInstance是static的,保证方法无需实例化获取方法,在类加载时就已创建. 扩展点:1.使用枚举方式的构建单例2.双重锁定时什么样的情况......
    • [SQL Server 2008R2] 有关于判断表、字段、存过等元素是否存在相关SQL写法
      表相关普通表查询普通表是否存在可以使用object_id函数,下面的例子是查询表“t_test”是否存在之后从而进行其他的DLL操作:ifobject_id('t_test')isnotnullbegin--如果表存在这段里面写相关逻辑select1end 临时表临时表同样可以用object_id但......
    • 单例模式细节
      提问单例模式有什么需要注意的问题回答类应该添加sealed防止继承懒汉式是线程不安全的,可以使用双锁定避免......
    • mybatis xml 中 大于、小于、等于 写法
      在*.xml中使用常规的<>=<=>=会与xml的语法存在冲突使用xml原生转义的方式进行转义字符名称字符串符号转义字符大于号>>小于号<<大于等于号>=>=小于等于号<=<=与&&amp;单引号'&apos;双引号""简单代码示例:select*fro......
    • 单例模式
      确保一个类只有一个实例,并提供一个全局访问点///<summary>///单例模式的实现///</summary>publicclassSingleton{//定义一个静态变量来保存类的实例privatestaticSingletonuniqueInstance;//定义一个标识确保线程同步privatestaticre......
    • Java 反射机制的一个简单例子.
      一、什么是反射:反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力。这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成绩。其中LEAD/LEAD++、Open......