java中的几种单例模式
目前比较常见的有4种(DCL为懒汉模式的线程安全版本)。
单例模式的实现一般需要满足以下条件:
1.构造方法私有化,实例属性私有化。
2.必须仅在类的内部完成实例的初始化过程。
3.提供公共静态方法,用以返回已经初始化完成的实例。
4.不可通过反射,反序列化方式获得新的实例。
1.饿汉模式:进行类初始化时就完成实例初始化的方式。可类比月光族,有钱就买。用不用不知道。
优势:由于初始化较早,所以相对于其他模式节省了这部分时间,效率较高。且多线程环境中保证安全运行。
劣势:在当前单例一直未被使用的场景下,资源利用率变的很低,另外无法从外界传递参数用来实例化。
/**
* @author txba6868
* @title: SingleTonTest
* @projectName javaAnalysis
* @date 2020/1/8 11:08
* @desc 单例模式
*/
public class SingleTonTest { //饿汉式:以空间换时间,类初始化时完成
private static SingleTonTest singleTonTest = new SingleTonTest(); public static SingleTonTest getInstance() {
return singleTonTest;
}
}
2.懒汉模式:有使用需求时通过调用getInstance()方法实现实例初始化。
优势:按需初始化,有效提高资源利用率。第一次调用可动态传参实例化。
劣势:初始化时出现时间成本,在多线程环境下有较高可能出现安全问题,造成多次实例化。
/**
* @author txba6868
* @title: SingleTonTest
* @projectName javaAnalysis
* @date 2020/1/8 11:08
* @desc 单例模式
*/
public class SingleTonTest { //懒汉式:以时间换空间,存在多线程安全问题
private static SingleTonTest singleTonTest = null; public static SingleTonTest getInstance() {
if (singleTonTest == null) {
singleTonTest = new SingleTonTest();
}
return singleTonTest;
}
}
3.DCL(doule check locking)主要是为了解决懒汉模式带来的线程安全问题做出的优化。但DCL仍旧存在安全问题,主要是因为程序中的“new”操作并非原子操作,代码注释中已写明,涉及到指令重排序及可见性问题,在java1.5之后JMM提供了volatile关键字,通过内存屏障的方式解决了该问题(网上有言论称volatile并未完美解决,仍然存在安全问题,还待博主继续探索下)。并且DCL由于内存屏障的原因,有可能屏蔽一些效率较高的代码优化,反而会引起效率的下降。
/**
* @author txba6868
* @title: SingleTonTest
* @projectName javaAnalysis
* @date 2020/1/8 11:08
* @desc 单例模式
*/
public class SingleTonTest { //构造方法私有化(略)
//DCL模式:同样存在线程安全问题,因为"new"操作不是一个原子操作,需要3步执行
//1.在内存中申请空间,2.实例中各参数初始化 3.将实例指向内存地址。
//由于指令重排序,会导致2和3的顺序发生变化,其他等待实例初始化的线程获取到不完整的实例。
private static volatile SingleTonTest singleTonTest = null; public static SingleTonTest getInstance() {
if (singleTonTest == null) {
synchronized (SingleTonTest.class) {
if (singleTonTest == null) {
singleTonTest = new SingleTonTest();
}
}
}
return singleTonTest;
}
}
4.静态内部类:同样是懒加载中的一种初始化方式。类初始化不会引起内部类的初始化。只有调用getInstance()方法时才会执行。该方法是effective java一书中的推荐方式。
优势:代码简洁,线程安全(依据为根据java规范,类的初始化有且仅有一次),按需初始化。
劣势:同饿汉模式,无法通过传递参数实例化对象。
/**
* @author txba6868
* @title: SingleTonTest
* @projectName javaAnalysis
* @date 2020/1/8 11:08
* @desc 单例模式
*/
public class SingleTonTest { //静态内部类
private static class SingleTonInnerClass {
private static SingleTonTest singleTonTest = new
SingleTonTest();
} public static SingleTonTest getInstance() {
return SingleTonInnerClass.singleTonTest;
}
//构造方法私有化
private SingleTonTest(){} }
另外,以上方式都存在两个同样的问题:可通过reflect创建实例;可通过反序列化生成新的实例。当然,我们可以通过在构造函数中加入一个标识阻止实例的二次创建。反序列化时通过重写方法直接返回当前实例。
但这样做无疑增加了代码的复杂性。
5.枚举类型:枚举方式在jvm层面可防御上述两种攻击方式。目前来看是一种较为安全的单例模式,不过枚举方式在内存方面的占用较静态方法略大。
/**
* @author txba6868
* @title: SingleTonTest
* @projectName javaAnalysis
* @date 2020/1/8 11:08
* @desc 单例模式
*/
public class SingleTonTest { //构造方法私有化
private SingleTonTest() {
} //获取单例对象
public static SingleTonTest getInstance() {
return SingleTon.INSTANCE.getInstance();
} private enum SingleTon {
INSTANCE;
private SingleTonTest singleTon; SingleTon() {
singleTon = new SingleTonTest();
} private SingleTonTest getInstance() {
return singleTon;
}
}
}
单例模式应用场景:spring IOC容器,日志处理/配置文件读取(后续会补充)。
参考:https://www.jianshu.com/p/f8267d6ac017(细说java中的几种单例模式)
引申:https://www.cnblogs.com/duanxz/p/3152574.html(单例-被废弃的DCL双重检查加锁)
https://www.jianshu.com/p/d9d9dcf23359(为什么说枚举是最好的单例实现)
// 构造方法私有化(略)
java中的几种单例模式的更多相关文章
- Java中的五种单例模式实现方法
[代码] Java中的五种单例模式实现方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 2 ...
- Java中的五种单例模式
Java模式之单例模式: 单例模式确保一个类只有一个实例,自行提供这个实例并向整个系统提供这个实例. 特点: 1,一个类只能有一个实例 2 自己创建这个实例 3 整个系统都要使用这个实例 例: 在下面 ...
- 快速理解Java中的五种单例模式
解法一:只适合单线程环境(不好) package test; /** * @author xiaoping * */ public class Singleton { private static S ...
- 快速理解Java中的七种单例模式
饿汉式(推荐) package concurencyv2.chapter1; public class SingletonV2 { private static final SingletonV2 i ...
- 快速理解Java中的五种单例模式(转)
解法一:只适合单线程环境(不好) package test; /** * @author xiaoping * */ public class Singleton { private static S ...
- [设计模式](转)Java中的24种设计模式与7大原则
*:first-child { margin-top: 0 !important; } body > *:last-child { margin-bottom: 0 !important; } ...
- JAVA基础学习之throws和throw的区别、Java中的四种权限、多线程的使用等(2)
1.throws和throw的区别 throws使用在函数外,是编译时的异常,throw使用在函数内,是运行时的异常 使用方法 public int method(int[] arr) throws ...
- JAVA中的四种引用以及ReferenceQueue和WeakHashMap的使用示例
简介: 本文主要介绍JAVA中的四种引用: StrongReference(强引用).SoftReferenc(软引用).WeakReferenc(弱引用).PhantomReference(虚引用) ...
- Java中的四种引用
引用定义 实际上,Java中存在四种引用,它们由强到弱依次是:强引用.软引用.弱引用.虚引用.下面我们简单介绍下这四种引用: 强引用(Strong Reference):通常我们通过new来创建一个新 ...
随机推荐
- linux服务器自动备份与删除postgres数据库数据
1.先创一个back.sh 文件,授权,然后在下面这个文件添加脚本 export PGPASSWORD='123456' #这是登录服务器密码cur_time=`date +%Y%m%d ...
- spring boot 中容器 Jetty、Tomcat、Undertow
spring boot 中依赖tomcat <dependency> <groupId>org.springframework.boot</groupId> < ...
- Java基础 -4.5
循环控制 在循环语句定义的时候还有两个控制语句:break.continue break主要的功能是退出整个循环结构 continue严格来讲只是结束当前的一次调用(结束当前循环) 当执行到了cont ...
- 分布式事务中间件 TCC-Transaction 源码分析 —— 项目实战
https://blog.csdn.net/lldouble/article/details/79455172
- Android Studio的HAXM不支持虚拟机
因为我的计算机是服务器,不支持虚拟机,所以报这个错了. 解决方式是直接连接物理手机,打开USB调试,安装驱动,运行项目即可.
- 写给想要入门python或者正在入门python的小朋友们
写在前面: 最近好像python挺火,虽然我也在天天写python,但是python毕竟是动态语言,就拿常被人吐槽的java来说,python绝大不多数地方是不如java的.python只能是你的一个 ...
- 115、Java中String类之使用concat进行字符串连接
01.代码如下: package TIANPAN; /** * 此处为文档注释 * * @author 田攀 微信382477247 */ public class TestDemo { public ...
- Eclipse传递main函数参数
在项目上右击 Run As->Run Configurations...->Arguments->在Program arguments:的文本框中输入你要传入的参数,若有几个参数则在 ...
- [多校联考]SLON!!!
题目描述 $SLON$是一个调皮的学生,为了让他静下心来,老师给他出了一道数学题:给定表达式$A$,$A$中含有变量$x$和$+,-,*,(,)$这些符号,括号成对出现,一个算术运算符均对应两个操作数 ...
- MySQL操作之DDL
目录 SQL语句的分类 DDL语句 SQL语句的分类 DDL(Data Definition Languages)语句:数据定义语言.这些语句定义了不同的数据段. 数据库.表.列.索引等数据库对象的定 ...