目前比较常见的有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中的几种单例模式的更多相关文章

  1. 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 ...

  2. Java中的五种单例模式

    Java模式之单例模式: 单例模式确保一个类只有一个实例,自行提供这个实例并向整个系统提供这个实例. 特点: 1,一个类只能有一个实例 2 自己创建这个实例 3 整个系统都要使用这个实例 例: 在下面 ...

  3. 快速理解Java中的五种单例模式

    解法一:只适合单线程环境(不好) package test; /** * @author xiaoping * */ public class Singleton { private static S ...

  4. 快速理解Java中的七种单例模式

    饿汉式(推荐) package concurencyv2.chapter1; public class SingletonV2 { private static final SingletonV2 i ...

  5. 快速理解Java中的五种单例模式(转)

    解法一:只适合单线程环境(不好) package test; /** * @author xiaoping * */ public class Singleton { private static S ...

  6. [设计模式](转)Java中的24种设计模式与7大原则

    *:first-child { margin-top: 0 !important; } body > *:last-child { margin-bottom: 0 !important; } ...

  7. JAVA基础学习之throws和throw的区别、Java中的四种权限、多线程的使用等(2)

    1.throws和throw的区别 throws使用在函数外,是编译时的异常,throw使用在函数内,是运行时的异常 使用方法 public int method(int[] arr) throws ...

  8. JAVA中的四种引用以及ReferenceQueue和WeakHashMap的使用示例

    简介: 本文主要介绍JAVA中的四种引用: StrongReference(强引用).SoftReferenc(软引用).WeakReferenc(弱引用).PhantomReference(虚引用) ...

  9. Java中的四种引用

    引用定义 实际上,Java中存在四种引用,它们由强到弱依次是:强引用.软引用.弱引用.虚引用.下面我们简单介绍下这四种引用: 强引用(Strong Reference):通常我们通过new来创建一个新 ...

随机推荐

  1. java是什么

    Java是一个纯的面向对象的程序设计语言 java是一种强类型语言,特点是: 1,跨平台 2,面向对象 3,简单易用 跨平台指的是只要有java虚拟机的平台,都可以运行java代码. Java继承了C ...

  2. Docker示例命令

    1.docker run -t -i -v /root/workspace/node:/home/exam:rw docker.io/node bin/sh    -t 给容器挂载一个伪终端    - ...

  3. 【转】Chrome开发者工具详解

    https://www.jianshu.com/p/7c8552f08e7a Chrome开发者工具详解(1)-Elements.Console.Sources面 Chrome开发者工具详解(2)-N ...

  4. centos6.9下 svn 1.7.10版本 编译安装

    svn安装推荐文章: 1.    http://blog.51cto.com/myhat/786950 2.    https://blog.csdn.net/test1280/article/det ...

  5. LauUI 的学习

    LayUI学习笔记 layer laydate layui 学习新技术方法:学习一个新技术,要去把它的文档通读一遍,不管你能不能读明白,就算你不明白也大概能知道它是怎么回事了,一回生二回熟,多读几遍, ...

  6. windows 10 遥控操作和传输文件

    传输文件命令 scp file user@192.168.1.1:/home/           file文件传到192.168.1.1/home/目录下 scp -r directory user ...

  7. Fescar分布式事务实现原理解析探秘

    前言 fescar发布已有时日,分布式事务一直是业界备受关注的领域,fescar发布一个月左右便受到了近5000个star足以说明其热度.当然,在fescar出来之前,已经有比较成熟的分布式事务的解决 ...

  8. 三 基于Java数组手写循环队列

    Code: package dataStucture2.stackandqueue; /** * 手写循环队列 * * @param <E> */ public class MyLoopQ ...

  9. Mp3下载

  10. Linux进程通信方式

    参考:https://www.cnblogs.com/yangykaifa/p/7295863.html