Java双重校验单例模式详解
单例模式双重检测java实现:
public class Singleton {
private volatile static Singleton instance = null; //#1
public static Singleton getInstance() {
if (instance == null) { //#2
synchronized (SingletonClass.class) { //#3
if(instance == null) { //#4
instance = new Singleton();
}
}
}
return instance;
}
1.1:为什么要使用volatile?
通常来说在堆中创建变量,会有两个步骤:
在堆中分配内存空间、执行初始化(就是new做得事情)
在栈中的本地变量表分配一个指向该内存区域的reference(等于号做得事情)
但JVM会进行编译优化,并不一定按照这样的顺序执行。在多线程环境下,若线程A创建instance,首先分配了reference的指针,此时线程B并发地去执行getInstance方法,那么会发现instance所指向的内存区域并不是null,那么线程B的getInstance方法则会返回这个instance,但实际上线程A仅仅是分配了这个指针,并没有在内存区域中完成初始化方法。
volatile禁止了JVM对指令顺序的优化,使得创建变量严格按照先分配内存再分配指针的顺序执行。
同时,如果没有volatile,某线程修改变量,并不会立即存入共享内存(主存),而是存入线程私有的一块高速缓存区域(在CPU中的cache),而volatile要求线程对变量修改完之后立即存入共享内存,保证了变量修改的可见性。
1.2:为什么要static?
保证单例对象是属于类的,而不是属于对象实例的,保证一个类只有一个变量。
3 为什么不给getInstance方法修饰synchronized,而是在这里给类上锁?
因为没有必要,如果在最外层判断出已有单例对象,则无需调用任何同步方法。而若给getInstance方法修饰synchronized,那么无论如何都有synchronized带来的额外开销(即便synchronize进行了大量优化)。
4 为什么需要第二层检验?
在多线程环境下,若没有语句#4,想象这样的场景:
线程A执行完#2
在#2、#3之间发生了线程切换,切换到线程B
线程B执行#3,获取到了锁,并进行instance初始化
切换回线程A,线程A执行#3,获取到了锁,并进行instance初始化
会发现instance被初始化了两次,因此必须进行第二层检验。
Java双重校验单例模式详解的更多相关文章
- Java设计模式之单例模式详解
在Java开发过程中,很多场景下都会碰到或要用到单例模式,在设计模式里也是经常作为指导学习的热门模式之一,相信每位开发同事都用到过.我们总是沿着前辈的足迹去做设定好的思路,往往没去探究为何这么做,所以 ...
- 9种Java单例模式详解(推荐)
单例模式的特点 一个类只允许产生一个实例化对象. 单例类构造方法私有化,不允许外部创建对象. 单例类向外提供静态方法,调用方法返回内部创建的实例化对象. 懒汉式(线程不安全) 其主要表现在单例类在外 ...
- java并发编程 | 锁详解:AQS,Lock,ReentrantLock,ReentrantReadWriteLock
原文:java并发编程 | 锁详解:AQS,Lock,ReentrantLock,ReentrantReadWriteLock 锁 锁是用来控制多个线程访问共享资源的方式,java中可以使用synch ...
- Java 8 Stream API详解--转
原文地址:http://blog.csdn.net/chszs/article/details/47038607 Java 8 Stream API详解 一.Stream API介绍 Java8引入了 ...
- java反射机制深入详解
java反射机制深入详解 转自:http://www.cnblogs.com/hxsyl/archive/2013/03/23/2977593.html 一.概念 反射就是把Java的各种成分映射成 ...
- 国际化,java.util.ResourceBundle使用详解
java.util.ResourceBundle使用详解 一.认识国际化资源文件 这个类提供软件国际化的捷径.通过此类,可以使您所编写的程序可以: 轻松地本地化或翻译成不同的 ...
- java之StringBuffer类详解
StringBuffer 线程安全的可变字符序列. StringBuffer源码分析(JDK1.6): public final class StringBuffer extends Abstract ...
- java.util.ResourceBundle使用详解
java.util.ResourceBundle使用详解 一.认识国际化资源文件 这个类提供软件国际化的捷径.通过此类,可以使您所编写的程序可以: 轻松地本地化或翻译成不同的 ...
- java之AbstractStringBuilder类详解
目录 AbstractStringBuilder类 字段 构造器 方法 public abstract String toString() 扩充容量 void expandCapacity(in ...
随机推荐
- 攻防世界-MISC:2017_Dating_in_Singapore
这是MISC高手进阶区的题目:题目如下: 点击下载附件一,得到一张pdf图片,除此之外就只有题目给的字符串了,不知道是什么意思(查看了一下WP)原来每一串通过"-"隔开的字符串代表 ...
- PHP 运行 mkdir() Permission Denied 的原因
使用lamp,在上传文件时,PHP执行 mkdir($path) , 出现没有权限的错误. 解决: 本次使用的时yii框架,所以首先确保 是apache的用户对web目录有权限,然后再给此用户加 r ...
- Java 17中对switch的模式匹配增强
还记得Java 16中的instanceof增强 吗? 通过下面这个例子再回忆一下: Map<String, Object> data = new HashMap<>(); d ...
- Spring 源码(10)Spring Bean 的创建过程(1)
Spring Bean的创建刚开始进行了一些准备工作,比如转换服务的初始化,占位符解析器的初始化,BeanDefinition元数据的冻结等操作,都是为了在创建Bean的过程中保证Bean的正确的创建 ...
- 思科,华为l2tp组网,家庭宽带,公司内网数据分离
拓扑 简介 办公网使用专线接入,拥有固定IP地址,网络出口使用防火墙做NAT,下联交换机接入服务器,办公电脑等,旁挂思科路由器做L2TP LNS 家庭宽带使用ADSL线路,华为路由器做拨号设备与DHC ...
- Centos7部署Redis集群
Redis简介 Redis(Remote Dictionary Server)是完全开源的.遵守BSD协议的.高性能的Key-Value数据库. Redis与其他Key-Value缓存产品有一下三个特 ...
- vue2 使用 swiper 轮播图效果
第一步.先安装swiper插件 npm install swiper@3.4.1 --save-dev 第二步.组件内引入swiper插件 import Swiper from 'swiper' im ...
- Net6 Xunit 集成测试
对于单元测试.集成测试大部分开发的朋友都懒得去写,因为这要耗费精力去设计去开发,做完项目模块直接postman 调用测试(当然这是一个选择,开发也中经常用到),但是如果测试需要多样化数据,各种场景模拟 ...
- 第31章 Spring bean 作用域
每日一句 I must say a word about fear. It is life's only true opponent. Only fear can defeat life. 这里必须说 ...
- 解决 AMD 笔记本不插电源时屏幕偏暗的问题
办法:关掉显卡设置里的 Vari-Bright 选项 最近换了锐龙版的笔记本,用着还不错,就是不插电源时看屏幕亮度不太适应,整体偏暗,有点费眼,差点就觉得 AMD 不 Yes 了.然后网上一顿找,发现 ...