java双重检测或枚举类实现线程安全单例(懒汉模式)
双重检测实现
/**
* 懒汉模式->双重同步锁单例模式
*/
public class SingletonExample5 {
private SingletonExample5() {
}
//volatile + 双重检测机制 -> 禁止指令重排序
private static volatile SingletonExample5 instance = null;
/**
* synchronized导致性能开销增加
*/
private static SingletonExample5 getInstance() {
if (null == instance) { //双重检测机制
synchronized (SingletonExample5.class) { //同步锁
if (null == instance) {
instance = new SingletonExample5();
}
}
}
return instance;
}
}
上述为经典的双重检测
实现java
单例类.
需要注意,如果单例实体instance
未被volatile
修饰,则双重检测
的实现方式线程不安全
.
从逻辑上,双重检测
是正确的,但这是建立在cpu
或者jvm
未对指令
进行重排序
操作.
将java
创建对象分为以下三个步骤执行:
- 分配对象内存空间;
- 初始化对象;
- instance指向分配的内存空间.
在实际的操作过程中,可能发生指令重排序
,选择可能场景:执行步骤为1、3、2
.
假设有A、B两个线程去执行getInstance
:
- A线程执行完1,3步骤,此时
instance
非空,但是对象尚未完成初始化操作: - B线程此时访问
instance
,发现非空,传递给用户使用. - B线程此时拿到的
instance
实例未完成初始化,后果自行想象.
因此,为了避免cpu
或者jvm
对指令进行重排序,使用volatile
强制避免重排序
即可实现线程安全.
Tips:
getInstance
函数可以被synchronized
以保证线程安全,但是synchronized
在高并发环境下会导致性能损耗严重
,因此我们下沉synchronized
至函数内部,尽可能缩小同步范围.
枚举类实现
/**
* 枚举模式:单词调用(需要时构造),线程安全
*/
@Slf4j
public class SingletonExample7 {
private SingletonExample7() {
}
private static SingletonExample7 getInstance() {
return Singleton.INSTANCE.getInstance();
}
private enum Singleton {
INSTANCE;
private SingletonExample7 singletonExample7;
//jvm保证方法只被调用一次
Singleton() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("枚举类构造函数运行");
singletonExample7 = new SingletonExample7();
}
public SingletonExample7 getInstance() {
return singletonExample7;
}
}
public static void main(String[] args) throws InterruptedException {
//测试:枚举类实现单例类是否是懒加载
for (int i = 0; i < 3; i++) {
log.info("枚举类实现单例");
Thread.sleep(2000);
}
System.out.println(getInstance().hashCode());
System.out.println(getInstance().hashCode());
}
}
使用枚举类
实现线程安全单例,相较于双重检测
方式较为简单.
jvm
保证枚举类
只会被调用一次,构造函数为私有.
此外,实现上述代码可以发现,枚举类
实现单例是懒加载
模式,只在getInstance
时创建并初始化对象.
PS:
如果您觉得我的文章对您有帮助,可以扫码领取下红包,谢谢!
java双重检测或枚举类实现线程安全单例(懒汉模式)的更多相关文章
- java面向对象程序设计(下)-枚举类
在某些情况下,一个类的对象是有限而且固定的,比如季节类,它只有4个对象;再比如行星类,目前只有8个对象,这些实例有限而且固定的类,在Java中被称为枚举类 JDK1.5新增了一个enum关键字,(它与 ...
- muduo网络库源码学习————线程本地单例类封装
muduo库中线程本地单例类封装代码是ThreadLocalSingleton.h 如下所示: //线程本地单例类封装 // Use of this source code is governed b ...
- 用私有构造器或者枚举类型强化SingleTon(单例)属性
单例(singleton)就是一个只实例化一次的类.使类成为单例可能会使它的测试变得困难,因为除非它实现了作为其类型的接口,否则不可能用模拟实现来代替这个单例.下面是几种实现单例的方法: 1.共有静态 ...
- 【Java基础】关于枚举类你可能不知道的事
目录 谈谈枚举 1. 枚举类的定义 2. 枚举类的底层实现 3. 枚举类的序列化实现 4. 用枚举实现单列 5. 枚举实例的创建过程是线程安全的 谈谈枚举 如果一个类的对象个数是有限的而且是不变的,我 ...
- 0029 Java学习笔记-面向对象-枚举类
可以创建几个对象? n多个:大部分的类,都可以随意创建对象,只要内存不爆掉 1个:比如单例类 有限的几个:采用单例类的设计思路,可以只允许创建少数的几个特定的对象:还有就是枚举类. 创建少数几个对象, ...
- Java中的enum枚举类
首先说说为什么要写这个enum枚举类吧,是群里有个新手问:怎样把enum类中的值遍历得到,其实自己用的也很少.自己也是确实不知道,于是我去网上搜了不少,总结了些,希望对大家有帮助:首先我说说怎样遍历枚 ...
- Java疯狂讲义笔记——枚举类
枚举类 ——Java5[基础知识]1,定义枚举类——关键字 enum (地位与class.interface相同).2,枚举类是一个特殊的类,可以有成员变量.方法,实现一个或多个接口,定义自己的构造器 ...
- JAVA中实现单例(Singleton)模式的八种方式
单例模式 单例模式,是一种常用的软件设计模式.在它的核心结构中只包含一个被称为单例的特殊类.通过单例模式可以保证系统中,应用该模式的类一个类只有一个实例.即一个类只有一个对象实例. 基本的实现思路 单 ...
- 【Java学习笔记之三十】详解Java单例(Singleton)模式
概念: Java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍三种:懒汉式单例.饿汉式单例.登记式单例. 单例模式有以下特点: 1.单例类只能有一个实例. 2.单例类必须自己创建 ...
随机推荐
- Python字符编码与转码
字符编码与转码 注: 该图转自 http://www.cnblogs.com/luotianshuai/p/5735051.html. Python2 解码,编码 #Python2 #-*- codi ...
- Maven常识
maven下面通常有四个文件夹: src/main/java -- 用来存放业务代码 src/test/java -- 用来存放测试代码 另有两个名为resource的文件夹,通常用来放置前两个文件夹 ...
- Kafka元数据缓存(metadata cache)
经常有人问的一个问题就是:Kafka broker到底是不是无状态的?网上有这样的说法: 正常情况下consumer会在消费完一条消息后线性增加这个offset.当然,consumer也可将offse ...
- 使用代码的方式给EntityFramework edmx 创建连接字符串
在构建上下文的时候动态生成连接字符串: /// <summary> /// 从配置生成连接 /// </summary> private static readonly str ...
- 关于Random(47)与randon.nextInt(100)的区别
参考https://blog.csdn.net/md_shmily92/article/details/44059313 相关文章random.nextInt()与Math.random()基础用法 ...
- BZOJ 1260:[CQOI2007]涂色paint
(⊙o⊙)-,常规课考试又炸了!目测此次我要完蛋了... 又玩脱了,考数学的时候装B装大了! 算了,先进入正题... 题目描述:Description假设你有一条长度为5的木版,初始时没有涂过任何颜色 ...
- bootstrap 选项卡的使用
1.页面中的tab 在做项目的时候用到了切换选项卡显示不同图表页面的 需求,如下图 就直接使用了bootstrapd的选项卡 学习源头: http://www.runoob.com/bootstrap ...
- 【反编译系列】一、反编译代码(dex2jar + jd-gui)和反编译资源(apktool)
版权声明:本文为HaiyuKing原创文章,转载请注明出处! [反编译系列]二.反编译代码(jeb) [反编译系列]三.反编译神器(jadx) [反编译系列]四.反编译so文件(IDA_Pro) 概述 ...
- RabbitMQ死信队列另类用法之复合死信
前言 在业务开发过程中,我们常常需要做一些定时任务,这些任务一般用来做监控或者清理任务,比如在订单的业务场景中,用户在创建订单后一段时间内,没有完成支付,系统将自动取消该订单,并将库存返回到商品中,又 ...
- windows代码,路径分割
BOOL SplitPathName( PWSTR MyXbpathBuffer, wstring& wdrive, wstring& wdir, wstring& wfnam ...