目前比较常见的有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(为什么说枚举是最好的单例实现)

// 构造方法私有化(略)

最新文章

  1. linux学习笔记--文件
  2. 一个完整的类用来读取OpenSSL生成的pem格式的x509证书
  3. Linux的硬链接为何不能链接目录
  4. jedis入门实例
  5. Kakfa揭秘 Day7 Producer源码解密
  6. Node.js权威指南 (8) - 创建HTTP与HTTPS服务器及客户端
  7. 分享一个nodejs写的小论坛
  8. [LeetCode] 55. Jump Game 解题思路
  9. 数据库系统原理及其应用总结---ShinePans
  10. 说说PHP的autoLoad自动加载机制
  11. c++ 正則表達式
  12. API网关Ocelot 使用Polly 处理部分失败问题
  13. JAVA学习笔记(4)—— 排序算法
  14. 【转】利用 selenium 的 webdrive 驱动 headless chrome
  15. swap
  16. 【剑指offer】复杂链表的复制
  17. xilinx 高速收发器Serdes深入研究-Comma码(转)
  18. java ATM模拟程序
  19. Android实现中文汉字笔划(笔画)、中文拼音排序、英文排序
  20. 【selenium】HTMLTestRunner测试报告生成

热门文章

  1. nginx的负载介绍
  2. centos将uwsgi添加为系统服务
  3. 吴裕雄--天生自然 JAVA开发学习:解决java.sql.SQLException: The server time zone value报错
  4. python学习第一课
  5. STM32L152笔记
  6. 58按之字形顺序打印二叉树 +队列访问使用front和back,栈才是top
  7. Python 基础之函数初识与函数参数
  8. SpringCloud+Eureka+Feign+Ribbon的简化搭建流程,加入熔断,网关和Redis缓存[2]
  9. 特约稿件 Java并发教程(Oracle官方资料)
  10. 学习:Android框架