目录

浅谈Java中单例模式的几种应用

第一种:懒汉式

第二种:饿汉式

第三种:双重检索式

第四种:注册登记式

第五种:内部类形式

浅谈Java中单例模式的几种应用

日常开发中,为了提高我们系统中对象的复用性,大多采用单例模式的写法,以达到在系统中重复利用对象的目的。下面小编为大家简单介绍几种日常开发中常见的单例模式写法,以供参考和使用!如果有疑问大家可以留言公共讨论,共同学习进步。

第一种:懒汉式

懒汉的方式正如字面意思,可以通俗的理解为:来活了我再开始干活!下面看下懒汉式的具体写法。

public class LazySingletonPattern {

/**

* 私有对象

*/

private static UserModel userModel;

/**

* 获取唯一实例

*

* @return

*/

public static synchronized UserModel getInstance() {

if (userModel == null) {

userModel = new UserModel();

}

return userModel;

}

}

从上面代码分析得知,程序加载时userModel对象是空的,当我们调用getInstance方法时,首先判断内存中是否有userModel对象,如果没有则创建一个,之后静态的userModel对象会一直驻留在外面本机的内存中。需要注意的是这里一定要加上synchronized关键字,来保证getInstance方法是线程安全的,否则可能导致的结果就是内存中会创建多个userModel对象。

第二种:饿汉式

饿汉式相对于其他方式是最简单也是最暴力的一种方式,如下代码:

public class HungrySingletonPattern {

/**

* 初始化静态UserModel

*/

private static UserModel userModel = new UserModel();

/**

* 唯一实例

* @return

*/

public static UserModel getInstance(){

return userModel;

}

}

代码中直接实例化UserModel对象,也就是在项目启动的时候就为我们创建好了一份userModel对象,这样的优点在于静态对象本身就是单例的,我们在使用的时候可以不考虑线程安全问题。缺点也是显而易见的,在程序初始化时就要为我们创建好这些对象放入到内存中,造成了空间的浪费。

第三种:双重检索式

双重检索的方式,可以说是在性能和安全两个角度找了一个平衡点,可以理解为懒汉式单例模式的加强版,既考虑性能又考虑安全性的问题。

public class DoubleCheckSingletonPattern {

/**

* 静态UserModel

*/

private static UserModel userModel;

/**

* 双重检索单例方式

*

* @return

*/

public static UserModel getInstance() {

if (userModel == null) {

synchronized (DoubleCheckSingletonPattern.class) {

if (userModel == null) {

userModel = new UserModel();

}

}

}

return userModel;

}

}

双重检查锁的优势就在于会优先验证一次userModel对象是否存在值,而不是像懒汉式一样优先加锁,这样导致了性能的浪费。虽说synchronized在1.6之后得到了很好的优化,但是在多线程竞争下依然不排除性能的浪费。双重检索可以降低锁的浪费,也同时保证了线程的安全。

隐患补充:这里隐藏着一个问题,当两个线程进来后,先获取锁的线程开始创建线程的同时,第二个线程进入判断,因为构造对象的过程可能会比较长,这时第一个线程还未完成对象的完整创建,但第二个线程会拿到一个不是null的值,从而认为已经构造完成,导致返回的类并非是一个完整的对象。解决方案可以通过volatile来解决这个问题,完美的解决了这个问题的还是推荐使用内部类的创建方式。

第四种:注册登记式

注册登记式更适合多实例场景的管理,当下最火的Spring框架中IOC容器就采用的这种方式来管理我们系统中的Bean对象,小编这里只做简单的示例,相对于Spring中的要简单的多,不喜勿喷。

public class RegistrySingletonPattern {

/**

* Map容器

*/

private final static Map objectsMap = new ConcurrentHashMap<>();

/**

* 获取实例

*

* @return

*/

public static synchronized Object getInstance() {

String key = "&userModel";

if (!objectsMap.containsKey(key)) {

objectsMap.put(key, new UserModel());

}

return objectsMap.get(key);

}

}

上面代码得知我们创建的单例对象全部保存在Map容器中,由Map容器统一管理我们的单例对象。

第五种:内部类形式

内部类可以说是比较有创意的一种方式了,避免资源的直接浪费,也同时保证了单例。

public class InnerClassSingletonPattern {

static {

System.out.println("父类加载了");

}

/**

* 获取实例

*

* @return

*/

public static UserModel getInstance() {

return UserModelSingleton.userModel;

}

/**

* 内部类

*/

static class UserModelSingleton {

static final UserModel userModel = new UserModel();

static {

System.out.println("子类加载了");

}

}

}

内部类不同于饿汉式和懒汉式,也算是集成了这两种方式的优点,程序启动后并不会初始化内部类,而当外部类调用内部类的方法时,才会初始化内部类的UserModel实例,保证在不浪费资源的情况下达到的单例模式的应用。

小结:

小编这里只是例举了几种在工作中常用的几种写法,有问题的地方还请大家及时指出,免的误导了其他同学。本文涉及到其他技术点,这里不做扩展讲解,大家可以去了解下多线程多面的知识,小编也还有许多需要学习的地方,还请大家多多指点。

java中单例的应用_浅谈Java中单例模式的几种应用相关推荐

  1. java方法区对象类型_浅谈Java内存区域与对象创建过程

    一.java内存区域 Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域.这些区域都有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有的区域则 ...

  2. java的向下转型_浅谈Java向下转型的意义

    一开始学习 Java 时不重视向下转型.一直搞不清楚向下转型的意义和用途,不清楚其实就是不会,那开发的过程肯定也想不到用向下转型. 其实向上转型和向下转型都是很重要的,可能我们平时见向上转型多一点,向 ...

  3. java字符串常量存哪里_浅谈JAVA中字符串常量的储存位置

    在讲述这些之前我们需要一些预备知识: Java的内存结构我们可以通过两个方面去看待它. 从该角度看的话Java内存结构包含以下部分:该部分内容可以结合:JVM简介(更加详细深入的介绍) 1.栈区:由编 ...

  4. php和java的区别菜鸟教程_浅谈Java和PHP的主要区别

    当谈到PHP与Java的差异性问题时,更多的是回答初学者的一些疑问.对于刚接触IT的同学来说,他们需要做好对未来职业的选择.所以是选择PHP还是选择Java更有利于自身的技术特点和发展前景.所以在解决 ...

  5. java类的命名规范_浅谈Java中的命名规范

    现代软件架构的复杂性需要协同开发完成,如何高效地协同呢? 答案是:制定一整套统一的规范. 无规矩不成方圆,无规范难以协同,比如,制订交通法规表面上是要限制行车权,实际上是保障公众的人身安全,试想如果没 ...

  6. java接口是干啥_浅谈Java接口

    接口(英文:Interface)是Java中非常重要的内容,初学的时候可能感受不深,但是在做项目的时候,对面向接口编程的运用就变得尤为重要,不过这是后话了.现在先讨论假如是刚刚接触接口这个概念,该怎么 ...

  7. scale和java比较_浅谈java中BigDecimal的equals与compareTo的区别

    这两天在处理支付金额校验的时候出现了点问题,有个金额比较我用了BigDecimal的equals方法来比较两个金额是否相等,结果导致金额比较出现错误(比如3.0与3.00的比较等). [注:以下所讲都 ...

  8. java同名函数_浅谈Java 继承接口同名函数问题

    在Java中如果一个类同时继承接口A与B,并且这两个接口中具有同名方法,会怎么样? 动手做实验: interface A{ void fun(); } interface B{ void fun(); ...

  9. java 中的排序_浅谈java中常见的排序

    浅谈java中常见的排序 学过java的人都知道,排序这一部分初次接触感觉还是有点难以理解,很多地方也会用到.然而,在java中常见的排序方法:冒泡排序,选择排序,插入排序等等.下面就让我们一起揭开他 ...

最新文章

  1. maven 内置参数
  2. Facebook:正变为下一个微信?
  3. ubuntu/mint 恢复模式 报read-only file system 的解决方法
  4. P4288 [SHOI2014]信号增幅仪 最小圆覆盖
  5. linux安装gcc运行时库,Linux安装gcc-6.1.0
  6. Wireshark条件过滤后的数据包保存
  7. MATLAB 高等数学中的应用
  8. NLPIR ICTCLAS2015分词系统的使用
  9. 10的6次方用java怎么写_10的6次方怎么写
  10. Xshell “所选的用户密钥未在远程主机上注册,请再试一次”SSH 登录远程linux服务器(良心整理)
  11. 飞信登录时SIPC认证失败解决
  12. echarts百分比柱形图
  13. 微信定向流量_使用定向流量包怎么算?微信定向流量包怎样计算流量?
  14. Spring Boot中的配置文件使用以及重新加载
  15. 如何用laragon框架运行php文件
  16. 分享一个xenserver服务器添加网卡后续一系列吐血三升的问题
  17. Axure 教程:Axure加载第三方脚本
  18. python调用程序call_Python调用外部程序——os.system()和subprocess.call()
  19. 方程求根的迭代法——牛顿迭代法
  20. 鸿蒙源码导读-01:蓝海与红海

热门文章

  1. map集合的遍历Key
  2. iOS系统中导航栏的转场解决方案与最佳实践
  3. 计算机毕业设计springboot棉花
  4. [Linux]CentOS7校准时间--NTP
  5. 一例人肉搜索-伊凡娜丢失的Sidekick手机
  6. 1222 - The used SELECT statements have a different number of columns
  7. 说话快,别人感觉太强势怎么办?
  8. keil5 MDK 中缺core_cm3.o 报错 解决办法
  9. java 对接快递100实时查询API接口
  10. 兴趣部落总是显示连接不到服务器,腾讯qq兴趣部落怎么没有了?腾讯QQ兴趣部落即将停运是什么原因...