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来创建一个新 ...
随机推荐
- Python 使用pillow 操作图像
文档:https://pillow.readthedocs.io/en/stable/index.html 计算机图像基础 颜色和RGBA值 计算机程序通常将图像中的颜色表示为 RGBA 值.RGBA ...
- Matlab利用subplot绘制多个图像
利用subplot绘制多个图像 subplot(m,n,p) subplot是将多个图画到一个平面上的函数,m是行,n是列,p是所要绘制图所在的位置 x = 0:0.1:100; sinY = sin ...
- 端口打开和关闭do while
;Author : Bing Song ;// ;Usage: modify “logfile" according to actual drictory getdir logdir #获取 ...
- tensorflow文本分类实战——卷积神经网络CNN
首先说明使用的工具和环境:python3.6.8 tensorflow1.14.0 centos7.0(最好用Ubuntu) 关于环境的搭建只做简单说明,我这边是使用pip搭建了python的 ...
- 学习笔记(15)- 保险行业的问答语料 insuranceqa_data
数据概览 ''' pool data are translated Chinese data with Google API from original English data ''' POOL_T ...
- 什么是Nib文件
Nib文件是一种特殊类型的资源文件,它用于保存iPhone OS或Mac OS X应用程序的用户接口.Nib文件是Interface Builder文档.通常您会使用Interface Builder ...
- 8.Memcache
1.概述 (1) Memcached是什么 Memcached是一款开源的.高性能的.分布式的内存对象缓存系统 (2) Memcached能干什么 最主要的功能就是:在内存中缓存数据,以减轻数据库负载 ...
- TortoiseGit+msysgit保存用户名和密码
本文以windows系统为例 保存用户名和密码 在C盘的c:\Users**qing** (或可能是C:\Users\Administrator) (替换自己的用户名)找到.gitconfig, 如果 ...
- main.js index.html与app.vue三者关系详解
main.js index.html与app.vue三者关系详解 2019年01月23日 11:12:15 Pecodo 阅读数 186 main.js与index.html是nodejs的项目启 ...
- ch13 事件(思维导图)