7种创建方式,带你理解Java的单例模式

创建,方式,理解,java,模式 · 浏览次数 : 60

小编点评

**单例模式的几种实现方式** **1.懒汉模式** * 创建类实例在第一次使用的时候进行创建。 * 线程安全,但代码复杂。 **2.饿汉模式** * 创建类实例在类装载的时候进行创建。 * 线程安全,但效率较低。 **3.懒汉模式(双重锁同步锁单例模式)** * 创建类实例在第一次使用的时候进行创建,并使用双重锁来防止指令重排序。 * 效率较高,但线程安全性较低。 **4.懒汉模式(双重锁同步锁单例模式)** * 创建类实例在第一次使用的时候进行创建,并使用双重锁来防止指令重排。 * 线程安全,但代码复杂。 **5.懒汉模式(双重锁同步锁单例模式)** * 创建类实例在第一次使用的时候进行创建,并使用双重锁来防止指令重排。 * 效率最高,但线程安全性较低。 **6.饿汉模式** * 在类装载的时候进行创建。 * 线程安全,但效率较低。 **7.枚举方式** * 在第一次使用的时候进行实例化。 * 线程安全,但代码复杂。

正文

本文分享自华为云社区《《Java极简设计模式》第01章:单例模式(Singleton)》,作者:冰 河。

单例设计模式

看几个单例对象的示例代码,其中有些代码是线程安全的,有些则不是线程安全的,需要大家细细品味,这些代码也是在高并发环境下测试验证过的。

  • 代码一:SingletonExample1

这个类是懒汉模式,并且是线程不安全的

package io.binghe.concurrency.example.singleton;

/**

* @author binghe

* @version 1.0.0

* @description 懒汉模式,单例实例在第一次使用的时候进行创建,这个类是线程不安全的

*/

public class SingletonExample1 {

private SingletonExample1(){}

private static SingletonExample1 instance = null;

public static SingletonExample1 getInstance(){

//多个线程同时调用,可能会创建多个对象

if (instance == null){

instance = new SingletonExample1();

}

return instance;

}

}
  • 代码二:SingletonExample2

饿汉模式,单例实例在类装载的时候进行创建,是线程安全的

package io.binghe.concurrency.example.singleton;

/**

* @author binghe

* @version 1.0.0

* @description 饿汉模式,单例实例在类装载的时候进行创建,是线程安全的

*/

public class SingletonExample2 {

private SingletonExample2(){}

private static SingletonExample2 instance = new SingletonExample2();

public static SingletonExample2 getInstance(){

return instance;

}

}
  • 代码三:SingletonExample3

懒汉模式,单例实例在第一次使用的时候进行创建,这个类是线程安全的,但是这个写法不推荐

package io.binghe.concurrency.example.singleton;

/**

* @author binghe

* @version 1.0.0

* @description 懒汉模式,单例实例在第一次使用的时候进行创建,这个类是线程安全的,但是这个写法不推荐

*/

public class SingletonExample3 {

private SingletonExample3(){}

private static SingletonExample3 instance = null;

public static synchronized SingletonExample3 getInstance(){

if (instance == null){

instance = new SingletonExample3();

}

return instance;

}

}
  • 代码四:SingletonExample4

懒汉模式(双重锁同步锁单例模式),单例实例在第一次使用的时候进行创建,但是,这个类不是线程安全的!!!!!

package io.binghe.concurrency.example.singleton;

/**

* @author binghe

* @version 1.0.0

* @description 懒汉模式(双重锁同步锁单例模式)

* 单例实例在第一次使用的时候进行创建,这个类不是线程安全的

*/

public class SingletonExample4 {

private SingletonExample4(){}

private static SingletonExample4 instance = null;

//线程不安全

//当执行instance = new SingletonExample4();这行代码时,CPU会执行如下指令:

//1.memory = allocate() 分配对象的内存空间

//2.ctorInstance() 初始化对象

//3.instance = memory 设置instance指向刚分配的内存

//单纯执行以上三步没啥问题,但是在多线程情况下,可能会发生指令重排序。

// 指令重排序对单线程没有影响,单线程下CPU可以按照顺序执行以上三个步骤,但是在多线程下,如果发生了指令重排序,则会打乱上面的三个步骤。

//如果发生了JVM和CPU优化,发生重排序时,可能会按照下面的顺序执行:

//1.memory = allocate() 分配对象的内存空间

//3.instance = memory 设置instance指向刚分配的内存

//2.ctorInstance() 初始化对象

//假设目前有两个线程A和B同时执行getInstance()方法,A线程执行到instance = new SingletonExample4(); B线程刚执行到第一个 if (instance == null){处,

//如果按照1.3.2的顺序,假设线程A执行到3.instance = memory 设置instance指向刚分配的内存,此时,线程B判断instance已经有值,就会直接return instance;

//而实际上,线程A还未执行2.ctorInstance() 初始化对象,也就是说线程B拿到的instance对象还未进行初始化,这个未初始化的instance对象一旦被线程B使用,就会出现问题。

public static SingletonExample4 getInstance(){

if (instance == null){

synchronized (SingletonExample4.class){

if(instance == null){

instance = new SingletonExample4();

}

}

}

return instance;

}

}

线程不安全分析如下:

当执行instance = new SingletonExample4();这行代码时,CPU会执行如下指令:

1.memory = allocate() 分配对象的内存空间

2.ctorInstance() 初始化对象

3.instance = memory 设置instance指向刚分配的内存

单纯执行以上三步没啥问题,但是在多线程情况下,可能会发生指令重排序。

指令重排序对单线程没有影响,单线程下CPU可以按照顺序执行以上三个步骤,但是在多线程下,如果发生了指令重排序,则会打乱上面的三个步骤。

如果发生了JVM和CPU优化,发生重排序时,可能会按照下面的顺序执行:

1.memory = allocate() 分配对象的内存空间

3.instance = memory 设置instance指向刚分配的内存

2.ctorInstance() 初始化对象

假设目前有两个线程A和B同时执行getInstance()方法,A线程执行到instance = new SingletonExample4(); B线程刚执行到第一个 if (instance == null){处,如果按照1.3.2的顺序,假设线程A执行到3.instance = memory 设置instance指向刚分配的内存,此时,线程B判断instance已经有值,就会直接return instance;而实际上,线程A还未执行2.ctorInstance() 初始化对象,也就是说线程B拿到的instance对象还未进行初始化,这个未初始化的instance对象一旦被线程B使用,就会出现问题。

  • 代码五:SingletonExample5

懒汉模式(双重锁同步锁单例模式)单例实例在第一次使用的时候进行创建,这个类是线程安全的,使用的是 volatile + 双重检测机制来禁止指令重排达到线程安全

package io.binghe.concurrency.example.singleton;

/**

* @author binghe

* @version 1.0.0

* @description 懒汉模式(双重锁同步锁单例模式)

* 单例实例在第一次使用的时候进行创建,这个类是线程安全的

*/

public class SingletonExample5 {

private SingletonExample5(){}

//单例对象 volatile + 双重检测机制来禁止指令重排

private volatile static SingletonExample5 instance = null;

public static SingletonExample5 getInstance(){

if (instance == null){

synchronized (SingletonExample5.class){

if(instance == null){

instance = new SingletonExample5();

}

}

}

return instance;

}

}
  • 代码六:SingletonExample6

饿汉模式,单例实例在类装载的时候(使用静态代码块)进行创建,是线程安全的

package io.binghe.concurrency.example.singleton;

/**

* @author binghe

* @version 1.0.0

* @description 饿汉模式,单例实例在类装载的时候进行创建,是线程安全的

*/

public class SingletonExample6 {

private SingletonExample6(){}

private static SingletonExample6 instance = null;

static {

instance = new SingletonExample6();

}

public static SingletonExample6 getInstance(){

return instance;

}

}
  • 代码七:SingletonExample7

枚举方式进行实例化,是线程安全的,此种方式也是线程最安全的

package io.binghe.concurrency.example.singleton;

/**

* @author binghe

* @version 1.0.0

* @description 枚举方式进行实例化,是线程安全的,此种方式也是线程最安全的

*/

public class SingletonExample7 {

private SingletonExample7(){}

public static SingletonExample7 getInstance(){

return Singleton.INSTANCE.getInstance();

}

private enum Singleton{

INSTANCE;

private SingletonExample7 singleton;

//JVM保证这个方法绝对只调用一次

Singleton(){

singleton = new SingletonExample7();

}

public SingletonExample7 getInstance(){

return singleton;

}

}

}

 

点击关注,第一时间了解华为云新鲜技术~

 

与7种创建方式,带你理解Java的单例模式相似的内容:

7种创建方式,带你理解Java的单例模式

介绍创建Java单例对象的七种方式,重点掌握哪些创建方式是线程安全的,哪些方式是线程不安全的,并能够在实际项目中灵活运用设计模式,编写可维护的代码。

[转帖]7 种提升 Spring Boot 吞吐量神技!

https://cloud.tencent.com/developer/article/2045348?areaSource=105001.6&traceId=7RuArY2Tm1MQWwQaMnx-Q 一、异步执行 实现方式二种: 1、 使用异步注解@aysnc、启动类:添加@EnableAsyn

【转帖】Linux 系统双网卡绑定 bond的7种模式

第一种模式:mod=0 ,即:(balance-rr) Round-robin policy(平衡抡循环策略)第二种模式:mod=1,即: (active-backup) Active-backup policy(主-备份策略)第三种模式:mod=2,即:(balance-xor) XOR poli

讯飞星火大模型 与New Bing实测对比

昨天科大讯飞发布了讯飞星火认知大模型,在发布会现场实测大模型的7种核心能力,并发布了它在教育、办公、汽车、数字员工领域的应用成果。科大讯飞董事长刘庆峰表示:认知大模型展示了通用人工智能的曙光,讯飞星火认知大模型已在文本生成、知识问答、数学能力3种能力上超越ChatGPT。NewBing 也全面开放给

Bridge 桥接模式简介与 C# 示例【结构型2】【设计模式来了_7】

〇、简介 1、什么是桥接模式? 一句话解释: 通过一个类的抽象,与另一个类的抽象关联起来,当做桥。此后不管两个抽象类的实现有多少种,均可以通过这个桥来将两个对象联系起来。 桥接,顾名思义就是用桥来连接河两岸,将原本不关联的两部分联系起来,且不影响两岸的各自演化,演化出来的不同对象仍可以通过这个桥连接

.NET性能系列文章一:.NET7的性能改进

这些方法在.NET7中变得更快 照片来自 CHUTTERSNAP 的 Unsplash 欢迎阅读.NET性能系列的第一章。这一系列的特点是对.NET世界中许多不同的主题进行研究、比较性能。正如标题所说的那样,本章节在于.NET7中的性能改进。你将看到哪种方法是实现特定功能最快的方法,以及大量的技巧和

Spring MVC 中使用 RESTFul 编程风格

1. Spring MVC 中使用 RESTFul 编程风格 @目录1. Spring MVC 中使用 RESTFul 编程风格2. RESTFul 编程风格2.1 RESTFul 是什么2.2 RESTFul风格与传统方式对比3. Spring MVC 中使用 RESTFul 编程风格(增删改查)

一文了解Spring Boot启动类SpringApplication

只有了解 Spring Boot 在启动时都做了些什么,我们才能在后续的实践的过程中更好地理解其运行机制,以便遇到问题能更快地定位和排查。

webdav协议及我的笔记方案(私有部署)

背景 用markdown用于文章写作,有几年时间了,不是很喜欢折腾,主要就是在电脑上写,用的笔记软件就是typora。由于里面有很多工作相关的,以及个人资料相关的(包含了各种账号、密码啥的),所以不敢往各种云服务上放,还是想着数据由自己来管着。 自己管数据的话,就是数据存储到哪里的问题,有很多朋友是

探秘数据库中的并行计算技术应用

本文简要说明了以Shared Nothing为代表的节点间并行处理技术,以及SMP节点内并行处理技术和它们在开源数据库中的应用。