关于单例的DCL方式分析
public class Singleton { /**
* 单例对象实例
*/
private volatile static Singleton instance = null; public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
这是一个典型的DCL单例,其中volatile在之前已经说过了,可以保证无论何时读取这个变量,都是读到内存中最新的值,无论何时写这个变量,都可以立即写到内存中。
但是并没有这么简单,在没有见volatile修饰instance时,在编译后,编译器会自动把第二个判断删除,因为编译器判断这个程序在执行过程中,这个值是不会改变的,编译器不考虑多线程的情况。加了volatile,是告诉编译器,这个变量随时有可能会被其他线程改变,这样编译器就不会把这两个判断优化成一个判断了。
同时,volatile的变量,可以保证对该变量的操作具有原子性,典型的例子是long和double型变量,通常需要分两步读写一个double变量,volatile修饰的double可以保证对一个double变量的操作的两部分不会被多线程插入。以及对引用类型赋值的,new一个实例的过程不会被其他线程插入(new在编译指令中是分成几步执行的,防止这几步在执行过程中被其他线程取这个变量值,取到一个不完整的实例)。可以简单的理解为对volatile变量的set和get方法加上了synchronized关键字,在new的过程中,整个都处在set中,所以不会被其他线程的get打断,取到不完整的引用。
原子性针对一个long或者double或者一个引用类型,对于引用类型,原子性是指在new实例的过程中,不会被其他线程取到,即不会被其他线程取到一个不完整的实例。这种原子性可以理解为new的过程处于一个synchronize段的set方法中,只有set结束才可以被get到,即new的整个过程都是处于set中的。也可以理解为指令重排序,禁止把new过程的指令与把引用赋值给变量的语句重排序,赋值只发生在new结束之后。
再次,在第二次判断if (instance == null)的时候,会再次取一次instance,再次取这个instance已经是所有线程最新的,每次修改的引用都会实时反映到主内存中。
关于单例的DCL方式分析的更多相关文章
- 关于java的volatile关键字与线程栈的内容以及单例的DCL
用volatile修饰的变量,线程在每次使用变量的时候,都会读取变量修改后的最新的值.volatile很容易被误用,用来进行原子性操作. package com.guangshan.test; pub ...
- Swift中编写单例的正确方式
在之前的帖子里聊过状态管理有多痛苦,有时这是不可避免的.一个状态管理的例子大家都很熟悉,那就是单例.使用Swift时,有许多方法实现单例,这是个麻烦事,因为我们不知道哪个最合适.这里我们来回顾一下单例 ...
- Swift中的单例的实现方式
单例在iOS日常开发中是一个很常用的模式.对于希望在 app 的生命周期中只应该存在一个的对象,保证对象的唯一性的时候,一般都会使用单例来实现功能.在OC单例的写法如下: @implementatio ...
- 单例---被废弃的DCL双重检查加锁
被废弃的单例的DCL双重检查加锁/* *单例模式 *单例模式,保证一个类仅有一个实例,并提供一个访问它的全局访问点. *加同步锁的单例模式,适合在多线程中使用. */ class Singleton{ ...
- Redis 单例、主从模式、sentinel 以及集群的配置方式及优缺点对比(转)
摘要: redis作为一种NoSql数据库,其提供了一种高效的缓存方案,本文则主要对其单例,主从模式,sentinel以及集群的配置方式进行说明,对比其优缺点,阐述redis作为一种缓存框架的高可用性 ...
- Hi,我们再来聊一聊Java的单例吧(转)
1. 前言 单例(Singleton)应该是开发者们最熟悉的设计模式了,并且好像也是最容易实现的——基本上每个开发者都能够随手写出——但是,真的是这样吗? 作为一个Java开发者,也许你觉得自己对单例 ...
- Unity 游戏框架搭建 2018 (二) 单例的模板与最佳实践
Unity 游戏框架搭建 2018 (二) 单例的模板与最佳实践 背景 很多开发者或者有经验的老手都会建议尽量不要用单例模式,这是有原因的. 单例模式是设计模式中最简单的也是大家通常最先接触的一种设计 ...
- 探索Scala(3)-- 单例对象
研究一下Scala语言的单例对象(Singleton Objects),为下一篇文章做准备. static不是keyword 上一篇文章提到过,interface并非Scala语言keyword,能够 ...
- java单例五种实现模式梳理
java单例五种实现模式 饿汉式(线程安全,调用效率高,但是不能延时加载) 一上来就把单例对象创建出来了,要用的时候直接返回即可,这种可以说是单例模式中最简单的一种实现方式.但是问题也比较明显.单例在 ...
随机推荐
- STC-51开发板-单片机控制数码管&按键&点阵综合操作
操作: 实现按下一个按键,对应的数码管和点阵显示相应的数字 代码: /* *******************数码管按键综合项目********************* */ #include ...
- linux 常用find
磁盘查找文件内容: find .|xargs grep x find . -exec grep x{} \; 磁盘查找文件名称: find / -name "httpd.conf" ...
- Python3使用csv模块csv.writer().writerow()保存csv文件,产生空行的问题
问题:csv.writer().writerow()保存的csv文件,打开时每行后都多一行空行 解决方法:在open()内增加一个参数newline='' 即可 问题现象: 1.代码 with ...
- .net 委托的用法
定义了两个委托 //Func有返回值:Action无返回值.两个委托 Func<int,int> f= a =>a+1;//参数,返回值: int reslut=f(5);//6
- datagrid数据表格的维护
想想刚开始学jsp, 用application做一个简单的数据库, 简单的注册页面, 跟这个相比就是过家家 <%@ page language="java" contentT ...
- Spring依赖注入:注解注入
注解注入顾名思义就是通过注解来实现注入, Spring和注入相关的常见注解有Autowired.Resource.Qualifier.Service.Controller.Repository.Com ...
- keras—神经网络CNN—MNIST手写数字识别
from keras.datasets import mnist from keras.utils import np_utils from plot_image_1 import plot_imag ...
- HttpClient(一)
package com.cmy.httpClient; import org.apache.commons.httpclient.HttpClient; import org.apache.commo ...
- Java数据类型与MySql数据类型对照表
这篇文章主要介绍了Java数据类型与MySql数据类型对照表,以表格形式分析了java与mysql对应数据类型,并简单讲述了数据类型的选择与使用方法,需要的朋友可以参考下 本文讲述了Java数据类型与 ...
- Tomcat设置默认时区
本文讲解如何在tomcat启动时设置JVM默认时区. 环境:JDK1.8.114 web容器:Tomcat 9 tomcat启动脚本 /etc/init.d/tomcat 操作系统ubuntu 16 ...