单例模式(饿汉式和懒汉式)

  以前学习单例的时候,只理解了简单部分。这次看DRP,对单例的饿汉式和懒汉式有了一些认识和对比。

   在实际的开发中,有些地方需要一个类只有一个实例。比如:网站在线人数的计数器,再比如IDE中的工具箱之类的等等。当需要这个类只有一个实例时,我们就需要使用到单例模式。单例模式有两种实现方式:懒汉式(延迟加载)和 饿汉式(预加载)。

   目前遇到的情况使用饿汉式的比较多,也因为它比较简单。代码:

[java] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. public class ClientManager {     
  2.       
  3.     private static ClientManager instance = new ClientManager();   //静态私有成员,已初始化  
  4.       
  5.     public ClientManager(){ }  
  6.       
  7.     public static ClientManager getInstance(){     //静态,不用同步(类加载时已初始化,不会有多线程的问题)  
  8.         return instance;  
  9.     }  
  10. }  
   饿汉式:在类加载时就完成了初始化,所以类加载较慢,但获取对象的速度快。这里getInstance()是static的,不用同步(类加载时已初始化,不会有多线程的问题)


   饿汉式程序运行过程中会节省时间,但是实例不管有没有用到都会占用空间。在这方面懒汉式似乎比饿汉式优化。我们先看看代码:

[java] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. public class ClientManager  
  2.  {  
  3.     private static ClientManager instance = null;  
  4.       
  5.     private ClientManager(){  
  6.           
  7.     }  
  8.   
  9.     public static  ClientManager getInstance(){     //静态,同步,公开访问点  
  10.         if(instance == null){  
  11.             return new ClientManager();  
  12.         }  
  13.         return instance;  
  14.     }  
  15. }  
    比较懒,在类加载时,不创建实例,因此类加载速度快,但运行时获取对象的速度慢。这里getInstance()是static的。我们来想象一下:要使用ClientManager,直接调用类的getInstance()方法。第一次的时候发现instance是null,然后就新建一个对象,返回出去;第二次再使用的时候,因为这个instance是static的,所以已经不是null了,因此不会再创建对象,直接将其返回。那么为什么有同步的问题?

    线程A希望使用ClientManager,调用getInstance()方法。因为是第一次调用,A就发现instance是null的,于是它开始创建实例,就在这个时候,CPU发生时间片切换,线程B开始执行,它要使用ClientManager,调用getInstance()方法,同样检测到instance是null——注意,这是在A检测完之后切换的,也就是说A并没有来得及创建对象——因此B开始创建。B创建完成后,切换到A继续执行,因为它已经检测完了,所以A不会再检测一遍,它会直接创建对象。这样,线程A和B各自拥有一个ClientManager的对象——单例失败!

    对于这种情况,我们很容易就想到加锁来解决。那么加锁后是怎么样的?

[java] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. public class ClientManager{   
  2.   
  3.   private static ClientManager instance = null;   
  4.       
  5.   public synchronized static ClientManager getInstance() {     //给方法加锁  
  6.     if(instance == null) {   
  7.       instance = new ClientManager();   
  8.     }   
  9.     return instance;   
  10.   }   
  11.       
  12.   private ClientManager() {   
  13.        
  14.   }   
  15.       
  16.   
  17. }  
   getInstance()加上同步锁,一个线程必须等待另外一个线程创建完成后才能使用这个方法,这就保证了单例的唯一性。但是还有出现这样一个性能问题:每次调用getInstants时都需要加锁,会降低运行速度。所以我们还可以进一步改进。

[java] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. public class ClientManager {   
  2.   
  3.   private  static ClientManager instance = null;   
  4.   
  5.   public static ClientManager getInstance() {   
  6.     if (instance == null) {   
  7.       synchronized (ClientManager.class) {   
  8.         if(instance == null) {   
  9.           instance = new ClientManager();   
  10.         }   
  11.       }   
  12.     }   
  13.     return instance;   
  14.   }   
  15.   
  16.   private ClientManager() {   
  17.   
  18.   
  19.   }   
   这样的方法可以双重锁定。我们一般用让线程每次都加锁,而只是实例未被创建的时候再加锁处理,同时也能保证多线程的安全。为什么要进行两次instance==null的判断,这个交给大家自己想一下吧。就按照上面线程A和线程B这样的方式。

   最后,总结一下饿汉式和懒汉式的区别:饿汉式类加载时已初始化,不会有多线程的问题,使用简单。懒汉式是在需要时才对类进行实例化,但是有多线程问题,需要该考虑怎么加锁的问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/351534.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

关于前端设置cookie

cookie既可以后端设置也可以在前端设置,例如登陆/注册功能,每次都要向服务器请求用户数据,这种就可以把cookie放到前端储存起来。 当网页要发http请求时,浏览器会先检查是否有相应的cookie,有则自动添加在request head…

使用React,Spring Boot和用户身份验证构建CRUD应用程序

建筑物身份管理,包括身份验证和授权? 尝试Stormpath! 我们的REST API和强大的Java SDK支持可以消除您的安全风险,并且可以在几分钟内实现。 注册 ,再也不会建立auth了! React是用于创建Web应用程序前端的最…

java基本数据类型所占长度_java基本数据类型长度详解

java基本数据类型基础知识机器数和真值机器数一个数在计算机中的二进制表示形式,叫做这个数的机器数机器数是带符号的,在计算机用一个数的最高位存放符号, 正数为0, 负数为1例如:dec 3 bit 00000011dec -3 bit 10000011真值将带符号位的机器数对应的真正数值称为机…

解释型语言和编译型语言的区别

解释型语言和编译型语言的区别 首先,我们编程都是用的高级语言(写汇编和机器语言的大牛们除外),计算机不能直接理解高级语言,只能理解和运行机器语言,所以必须要把高级语言翻译成机器语言,计算机才能运行高级语言所编写…

解决tomcat中文传输乱码问题

<Connector URIEncoding"utf-8" connectionTimeout"20000" encoding"utf-8" port"8080" protocol"HTTP/1.1" redirectPort"8443"/> 在server.xml中找到这句即可&#xff0c;加上URIEncodingUTF-8即可。转载…

关于java结构中描述正确的是_下列关于Java中类的构造方法的描述,正确的是()...

A&#xff1a;构造函数没有返回值&#xff0c;也不能用void修饰。如果不小心给构造函数前面添加了返回值类型&#xff0c;那么这将使这个构造函数变成一个普通的方法&#xff0c;在运行时将产生找不到构造方法的错误。C&#xff1a;super(参数)&#xff1a;调用父类中的某一个构…

如何合理地估算线程池大小?

如何合理地估算线程池大小&#xff1f; 这个问题虽然看起来很小&#xff0c;却并不那么容易回答。大家如果有更好的方法欢迎赐教&#xff0c;先来一个天真的估算方法&#xff1a;假设要求一个系统的TPS&#xff08;Transaction Per Second或者Task Per Second&#xff09;至少为…

使用Arquillian,Docker和Selenium使Web UI测试再次变得出色(第1部分)

问题简介 大多数时候&#xff0c;当您需要为Web UI编写功能测试/端到端测试时&#xff0c;您最终会使用Selenium &#xff0c;它可以被视为Java世界中用于Web UI测试的事实上的工具。 我确定您已经将其用于此类测试。 但是可能同时&#xff0c;您遇到了功能测试中一些最常见的…

os sys hashlib

os模块 os模块是与操作系统交互的一个接口​ ?123456789101112131415161718192021222324252627282930313233343536<em>#和文件夹相关os.makedirs(dirname1/dirname2) 可生成多层递归目录os.removedirs(dirname1) 若目录为空&#xff0c;则删除&#xff0c;并递归到…

mysql 打包 脚本_windows下mysql自动备份压缩打包时间命名批处理脚本

我在此文章上做修改&#xff1a;把时间修改成不记录小时分和秒  新建一个名字后缀为“。bat”的文件  set d%date:~0,10%  set d%d:-%  set t%time:~0,8%  set t%t::%  set dzxpathmysql%p%%d%.sql  set ucpathuc%p%%d%%t%.sql  set folderd:\test\  echo of…

java sql 登录失败_java – 接收连接到SQL Server 2008的SQLException“用户登录失败”

我试图通过Java连接到SQL Server 2008.>我已将sqljdbc4.jar添加到我的项目库中.>没有为访问数据库的数据库设置用户名和密码(Windows身份验证).> 1433端口正在侦听,但我仍然收到此异常&#xff1a;SQL Exception: com.microsoft.sqlserver.jdbc.SQLServerException: L…

js-for (var in )遍历顺序乱了

存放的key 为如下&#xff1a; “01”&#xff0c;“02”&#xff0c;“03”&#xff0c;“10”&#xff0c;“11”&#xff0c;“12” 遍历之后“10”&#xff0c;“11”&#xff0c;“12”&#xff0c; “01”&#xff0c;“02”&#xff0c;“03”&#xff0c; 解决办法&…

springboot ---坑 tomcat部署springboot 一直运行不起来

1、首先部署springboot项目的tomcat的版本必须在8.0之后 2、springboot 同样是基于maven的&#xff0c;那么在pom.xml中的tomcat的依赖&#xff1a; <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web&l…

Java新手造假_老板居然让我在Java项目中“造假”

1. 前言老板说&#xff0c;明天甲方要来看产品&#xff0c;你得造点数据&#xff0c;而且数据必须是“真”的&#xff0c;演示效果要好看一些&#xff0c;这样他才会买我们的产品&#xff0c;我好明年给你换个嫂子。一般开发接到这种过分要求都不会很乐意去做&#xff0c;这完全…

设计模式 四人帮_四人帮–代理设计模式

设计模式 四人帮代理是另一种结构设计模式 &#xff0c;可以“代表”另一个对象或“代替”另一个对象以访问后面的对象。 何时使用此模式&#xff1f; 当我们需要创建一个包装来覆盖客户端的主要对象的复杂性时&#xff0c;将使用代理模式。 有哪些使用场景&#xff1f; 虚…

uniq 去除重复命令使用方法介绍

Linux Shell学习&#xff1a;uniq命令使用方法介绍uniq命令的作用&#xff1a;显示唯一的行&#xff0c;对于那些连续重复的行只显示一次&#xff01;接下来通过实践实例说明. [关键字] Linux Shell uniq 看test.txt文件的内容&#xff0c;可以看到其中的连续重复行 [roothexu.…

sqoop导数据出现问题

执行下面命令的时候报错 ./sqoop import \ --connect jdbc:mysql://mini1:3306/userdb \ --username root \ --password 123456 \ --table emp --m 1 ERROR manager.SqlManager: Error executing statement: java.sql.SQLException: Access denied for user rootmini1 (using p…

java导出jar带第三方库_在.jar文件中导出java库

我仍然是java的新手,我对导出.jar文件非常新.我有一个小游戏,我想发送给一些朋友,我被告知在另一个问题,我应该将它导出到一个可执行的jar文件.好吧,我终于在我的计算机上工作了但是当我把它发送给其他人时它不起作用,因为他们没有图书馆.我正在导入objectdraw库,没有它我的程序…

15分钟内使用Twilio和Stormpath在Spring Boot中进行身份管理

建筑物身份管理&#xff0c;包括身份验证和授权&#xff1f; 尝试Stormpath&#xff01; 我们的REST API和强大的Java SDK支持可以消除您的安全风险&#xff0c;并且可以在几分钟内实现。 注册 &#xff0c;再也不会建立auth了&#xff01; 今天&#xff0c;不到30秒左右的时间…

Spark系列之:使用spark合并hive数据库多个分区的数据到一个分区中

Spark系列之&#xff1a;使用spark合并hive数据库多个分区的数据到一个分区中 把两个分区的数据合并到同一个分区下把其中一个分区的数据通过append方式添加到另一个分区即可 %spark val df spark.sql("select * from optics_prod.product_1h_a where datetime202311142…