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 ...
随机推荐
- oauth协议原理
oauth协议关系图(如获取微信用户信息): oauth一般授权步骤:
- 开发并发布npm包,支持TypeScript提示,rollup构建打包
前言: 工作了几年,想把一些不好找现成的库的常用方法整理一下,发布成npm包,方便使用.也学习一下开发发布流程. 主要用到的工具:npm. 开发库:babel.typescript.rollup.es ...
- stm32F103RCT6的DMA使用经历
DMA可以直接传输数据,减少了CPU的负担,是个很好的功能,但是用的时候难免会一头雾水.这次做个小小的串口收发程序就碰到了许多问题. 之前没有注意,选择了DMA的circular模式,然后奇怪的事 ...
- ucore lab7 同步互斥机制 学习笔记
管程的设计实在是精妙,初看的时候觉得非常奇怪,这混乱的进程切换怎么能保证同一时刻只有一个进程访问管程?理清之后大为赞叹,函数中途把前一个进程唤醒后立刻把自己挂起,完美切换.后一个进程又在巧妙的时机将自 ...
- 干货 | Keepalived高可用服务配置实例
一个执着于技术的公众号 Keepalived系列导读 Keepalived入门学习 keepalived安装及配置文件详解 前言 在前面的章节中,我们学习了Keepalived简介.原理.以及Keep ...
- js动态生成vue组件
代码奉上 install (Vue, options) { Vue.prototype.$message = function (message){ let Constructor = Vue.ext ...
- docker 灵活的构建 php 环境
地址: https://github.com/ydtg1993/server 使用docker搭建灵活的线上php环境 有时候你可能不太需要一些别人已经集成了的包或者镜像 ...
- 2. 假设当前文件夹中data.csv文件中存放了2020年某饭店营业额,第一列为日期(如2020-02-03),第二列为每天交易额(如3560),文件中第一行为表头,其余行为实 际数据。
假设当前文件夹中data.csv文件中存放了2020年某饭店营业额,第一列为日期(如2020-02-03),第二列为每天交易额(如3560),文件中第一行为表头,其余行为实 际数据.编写程序,完成下 ...
- 手写vue路由
目录 一.简易demo 二.Vue-Router传参方式 三.进阶-路由导航 一.简易demo // routes注册 import Vue from "vue"; // impo ...
- 探索ABP基础架构-下
配置应用程序 ASP.NET Core 的配置系统提供了一个基于键值对的配置方法.它是一个可扩展的系统,可以从各种资源中读取键值对,例如 JSON 设置文件.环境变量.命令行参数等等. 设置配置值 默 ...