java中单例的应用_浅谈Java中单例模式的几种应用
目录
浅谈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中单例模式的几种应用相关推荐
- java方法区对象类型_浅谈Java内存区域与对象创建过程
一.java内存区域 Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域.这些区域都有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有的区域则 ...
- java的向下转型_浅谈Java向下转型的意义
一开始学习 Java 时不重视向下转型.一直搞不清楚向下转型的意义和用途,不清楚其实就是不会,那开发的过程肯定也想不到用向下转型. 其实向上转型和向下转型都是很重要的,可能我们平时见向上转型多一点,向 ...
- java字符串常量存哪里_浅谈JAVA中字符串常量的储存位置
在讲述这些之前我们需要一些预备知识: Java的内存结构我们可以通过两个方面去看待它. 从该角度看的话Java内存结构包含以下部分:该部分内容可以结合:JVM简介(更加详细深入的介绍) 1.栈区:由编 ...
- php和java的区别菜鸟教程_浅谈Java和PHP的主要区别
当谈到PHP与Java的差异性问题时,更多的是回答初学者的一些疑问.对于刚接触IT的同学来说,他们需要做好对未来职业的选择.所以是选择PHP还是选择Java更有利于自身的技术特点和发展前景.所以在解决 ...
- java类的命名规范_浅谈Java中的命名规范
现代软件架构的复杂性需要协同开发完成,如何高效地协同呢? 答案是:制定一整套统一的规范. 无规矩不成方圆,无规范难以协同,比如,制订交通法规表面上是要限制行车权,实际上是保障公众的人身安全,试想如果没 ...
- java接口是干啥_浅谈Java接口
接口(英文:Interface)是Java中非常重要的内容,初学的时候可能感受不深,但是在做项目的时候,对面向接口编程的运用就变得尤为重要,不过这是后话了.现在先讨论假如是刚刚接触接口这个概念,该怎么 ...
- scale和java比较_浅谈java中BigDecimal的equals与compareTo的区别
这两天在处理支付金额校验的时候出现了点问题,有个金额比较我用了BigDecimal的equals方法来比较两个金额是否相等,结果导致金额比较出现错误(比如3.0与3.00的比较等). [注:以下所讲都 ...
- java同名函数_浅谈Java 继承接口同名函数问题
在Java中如果一个类同时继承接口A与B,并且这两个接口中具有同名方法,会怎么样? 动手做实验: interface A{ void fun(); } interface B{ void fun(); ...
- java 中的排序_浅谈java中常见的排序
浅谈java中常见的排序 学过java的人都知道,排序这一部分初次接触感觉还是有点难以理解,很多地方也会用到.然而,在java中常见的排序方法:冒泡排序,选择排序,插入排序等等.下面就让我们一起揭开他 ...
最新文章
- maven 内置参数
- Facebook:正变为下一个微信?
- ubuntu/mint 恢复模式 报read-only file system 的解决方法
- P4288 [SHOI2014]信号增幅仪 最小圆覆盖
- linux安装gcc运行时库,Linux安装gcc-6.1.0
- Wireshark条件过滤后的数据包保存
- MATLAB 高等数学中的应用
- NLPIR ICTCLAS2015分词系统的使用
- 10的6次方用java怎么写_10的6次方怎么写
- Xshell “所选的用户密钥未在远程主机上注册,请再试一次”SSH 登录远程linux服务器(良心整理)
- 飞信登录时SIPC认证失败解决
- echarts百分比柱形图
- 微信定向流量_使用定向流量包怎么算?微信定向流量包怎样计算流量?
- Spring Boot中的配置文件使用以及重新加载
- 如何用laragon框架运行php文件
- 分享一个xenserver服务器添加网卡后续一系列吐血三升的问题
- Axure 教程:Axure加载第三方脚本
- python调用程序call_Python调用外部程序——os.system()和subprocess.call()
- 方程求根的迭代法——牛顿迭代法
- 鸿蒙源码导读-01:蓝海与红海
热门文章
- map集合的遍历Key
- iOS系统中导航栏的转场解决方案与最佳实践
- 计算机毕业设计springboot棉花
- [Linux]CentOS7校准时间--NTP
- 一例人肉搜索-伊凡娜丢失的Sidekick手机
- 1222 - The used SELECT statements have a different number of columns
- 说话快,别人感觉太强势怎么办?
- keil5 MDK 中缺core_cm3.o 报错 解决办法
- java 对接快递100实时查询API接口
- 兴趣部落总是显示连接不到服务器,腾讯qq兴趣部落怎么没有了?腾讯QQ兴趣部落即将停运是什么原因...