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来创建一个新 ...
随机推荐
- Pycharm创建一个Django项目
1.创建项目 如果本地没有安装与所选python版本对应Django版本,pycharm会自动下载相应的版本: 创建后运行项目,默认页面为http://127.0.0.1:8000/,打开后: 出现上 ...
- 泛型DAO模型设计
aaarticlea/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsKC
- 两台W7系统的电脑,A电脑可以ping通B电脑,B电脑ping不通A电脑。
https://zhidao.baidu.com/question/1946500242424659908.html 打开控制面板-系统和安全-防火墙-允许程序-文件和打印机共享(勾选) 局域网共享是 ...
- 吴裕雄--天生自然TensorFlow2教程:输出方式
sigmoid out' = sigmoid(out) # 把输出值压缩在0-1 import tensorflow as tf a = tf.linspace(-6., 6, 10) a tf.si ...
- hexo 安装和部署
因为投递论文需要个人网站,所以今天又来了一次hexo 安装和部署. 参考官方文档:https://hexo.io/zh-cn/docs/ git是需要的哈.自行安装 node需要大于8.10 node ...
- Linux软Raid--mdadm命令
mdadm:为软RAID提供管理界面,RAID设备可命名为/dev/md0./dev/md1./dev/md2./dev/md3等 命令的语法格式:mdadm[mode] <raiddevice ...
- 【转】android之在activity中控制另一个activity的UI更新_如何在activity之间传递handler
来自:http://blog.csdn.net/jason0539/article/details/18055259 遇到一个问题,需要在一个activity中控制另一个acitivity做一些更新, ...
- uniapp - 手机调试 ( vivo )
打开开发者选项,打开USB设置,把默认USB选项改成MIDI模式,就可以检测到手机
- ServletContext简介
什么是SercletContext ServletContext官方叫servlet上下文.服务器会为每一个工程创建一个对象,这个对象就是ServletContext对象.这个对象全局唯一,而且工程内 ...
- 零基础学完Python的7大就业方向,哪个赚钱多?
“ 我想学 Python,但是学完 Python 后都能干啥 ?” “ 现在学 Python,哪个方向最简单?哪个方向最吃香 ?” “ …… ” 相信不少 Python 的初学者,都会遇到上面的这些问 ...