前言 从Java内存模型出发,结合并发编程中的原子性.可见性.有序性三个角度分析volatile所起的作用,并从汇编角度大致说了volatile的原理,说明了该关键字的应用场景:在这补充一点,分析下volatile是怎么在单例模式中避免双检锁出现的问题的.   并发编程的3个条件 1.原子性:要实现原子性方式较多,可用synchronized.lock加锁,AtomicInteger等,但volatile关键字是无法保证原子性的: 2.可见性:要实现可见性,也可用synchronized.loc…
最初的代码 在最近的项目中,写出了这样的一段代码 private static SomeClass instance; public SomeClass getInstance() { if (null == instance) { instance = new SomeClass(); } return instance; } 然后在Code Review的时候被告知在多线程的情况下,这样写可能会导致instance有多个实例.比如下面这种情况: Time Thread A Thread B…
背景:我们在实现单例模式的时候往往会忽略掉多线程的情况,就是写的代码在单线程的情况下是没问题的,但是一碰到多个线程的时候,由于代码没写好,就会引发很多问题,而且这些问题都是很隐蔽和很难排查的. 例子1:没有volatile修饰的uniqueInstance public class Singleton { private static Singleton uniqueInstance; private Singleton(){ } public static Singleton getInsta…
对象部分初始化:原理以及验证代码(双重检查锁与volatile相关) 对象部分初始化被称为 Partially initialized objects / Partially constructed objects / Incompletely initialized objects 这三种不同的说法描述的是同一种情况,即指令重排序(reorder)导致未完全初始化的对象被使用,这会导致某些错误的发生. 文章纯原创,转载请表明地址 目录 对象部分初始化:原理以及验证代码(双重检查锁与volati…
双重检查锁定(Double check locked)模式经常会出现在一些框架源码中,目的是为了延迟初始化变量.这个模式还可以用来创建单例.下面来看一个 Spring 中双重检查锁定的例子. 这个例子中需要将配置文件加载到 handlerMappings中,由于读取资源比较耗时,所以将动作放到真正需要 handlerMappings 的时候.我们可以看到 handlerMappings 前面使用了volatile .有没有想过为什么一定需要 volatile?虽然之前了解了双重检查锁定模式的原理…
Java基础教程:多线程杂谈——双重检查锁与Volatile 双重检查锁 有时候可能需要推迟一些高开销的对象初始化操作,并且只有在使用这些对象时才进行初始化.此时程序员可能会采用延迟初始化.但要正确实现线程安全的延迟初始化需要一些技巧,否则很容易出现问题.比如,下面是非线程安全的延迟初始化对象的示例代码: public class A{ private Instance instance; public Instance getInstance(){ if(instance==null){ in…
搬以前写的博客[2014-12-30 16:04] 在web应用中服务器面临的是大量的访问请求,免不了多线程程序,但是有时候,我们希望在多线程应用中的某一个类只能新建一个对象的时候,就会遇到问题. 首先考虑单线程,如果要求只能新建一个对象,那么构造函数我们要设为private.简单的想法: class singleton{ private singleton(){ //..... } private static singleton instance; public static singlet…
编译指令 :javac Test.java 反编译指令: javap -v Test 代码 public class ObjectTest { int m = 8; public static void main(String[] args) { ObjectTest o = new ObjectTest(); } } 安装jclasslib插件后,可以看到这个类的clazz文件: 如图所示: 这个是 对象的创建过程, 这个过程中有个半初始化状态, 这里的 invokespecial 和 ast…
一个典型的单例模式构建对象的双重检查锁如下: static Singleton * getSingleObject() { if(singleObject==NULL) { lock(); if(singleObject==NULL) { singleObject = new Singleton(); } unlock(); } return singleObject; } 该代码的逻辑是:getSingleObject()函数获得对象,如果对象不存在则创建,反之则直接返回.考虑到线程安全,创建…
单例类在Java开发者中非常常用,但是它给初级开发者们造成了很多挑战.他们所面对的其中一个关键挑战是,怎样确保单例类的行为是单例?也就是说,无论任何原因,如何防止单例类有多个实例.在整个应用生命周期中,要保证只有一个单例类的实例被创建,双重检查锁(Double checked locking of Singleton)是一种实现方法.顾名思义,在双重检查锁中,代码会检查两次单例类是否有已存在的实例,一次加锁一次不加锁,一次确保不会有多个实例被创建.顺便提一下,在JDK1.5中,Java修复了其内…
一切真是有缘,上午刚刚看完单例模式,还在为其中的代码块同步而兴奋,下午就遇见这篇文章:双重检查锁定与延迟初始化.我一看,文章开头语出惊人,说这是一种错误的优化,我说,难道上午学的东西下午就过时了吗?仔细一看,发现了volatile的用处百度百科:violiate,而这正是上午我阅读时不得其解的地方,为什么要用这个呢,在<Head First设计模式>中只是简单说为了让多线程正确工作.而这篇文章,恰恰解决了我的这个疑惑,也就是uniqueInstance = new Instance()其实是分…
问题引入 Java中实现单例模式,一般性的做法是如下方式: class Singleton { private static Singleton INSTANCE = null; private Singleton() {} public static getInstance() { if (null == INSTANCE) { // <-- 此处如果有多个执行流同时进入,会造成多次初始化 INSTANCE = new Singleton(); } return INSTANCE; } } 上…
并发编程情况下有三个要点:操作的原子性.可见性.有序性. volatile保证了可见性和有序性,但是并不能保证原子性. 首先看一下DCL(双重检验锁)的实现: public class Singleton { private volatile static Singleton singleton; private Singleton (){} public static Singleton getSingleton() { if (singleton == null) { synchronize…
这个 Java 问题也常被问: 什么是线程安全的单例,你怎么创建它.好吧,在Java 5之前的版本, 使用双重检查锁定创建单例 Singleton 时,如果多个线程试图同时创建 Singleton 实例,则可能有多个 Singleton 实例被创建.从 Java 5 开始,使用 Enum 创建线程安全的Singleton很容易.但如果面试官坚持双重检查锁定,那么你必须为他们编写代码.记得使用volatile变量.…
MSDN上说: volatile 关键字指示一个字段可以由多个同时执行的线程修改. 声明为 volatile 的字段不受编译器优化的限制. 这样可以确保该字段在任何时间呈现的都是最新的值. volatile 关键字可应用于以下类型的字段: 引用类型. 指针类型(在不安全的上下文中). 请注意,虽然指针本身可以是可变的,但是它指向的对象不能是可变的. 换句话说,您无法声明“指向可变对象的指针”. 类型,如 sbyte.byte.short.ushort.int.uint.char.float 和…
单例模式DoubleCheck 锁问题 先贴代码 public class DoubleCheckSingleton { private static DoubleCheckSingleton instance = null; public static DoubleCheckSingleton getInstance(){ if(instance==null){ synchronized (DoubleCheckSingleton.class) { if (instance == null)…
今天,让我们一起来探讨 Java 并发编程中的知识点:volatile 关键字 本文主要从以下三点讲解 volatile 关键字: volatile 关键字是什么? volatile 关键字能解决什么问题?使用场景是什么? volatile 关键字实现的原理? volatile 关键字是什么? 在 Sun 的 JDK 官方文档是这样形容 volatile 的: The Java programming language provides a secondmechanism, volatile f…
Java的volatile关键字在JDK源码中经常出现,但是对它的认识只是停留在共享变量上,今天来谈谈volatile关键字. volatile,从字面上说是易变的.不稳定的,事实上,也确实如此,这个关键字的作用就是告诉编译器,只要是被此关键字修饰的变量都是易变的.不稳定的.那为什么是易变的呢?因为volatile所修饰的变量是直接存在于主内存中的,线程对变量的操作也是直接反映在主内存中,所以说其是易变的. 一.Java内存模型 Java内存模型规定所有的变量都是存在主存当中(类似于前面说的物理…
原文地址:http://tengj.top/2016/05/06/threadvolatile4/ <h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>今天介绍下volatile关键字,volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争…
Java的volatile关键字在JDK源码中经常出现,但是对它的认识只是停留在共享变量上,今天来谈谈volatile关键字. volatile,从字面上说是易变的.不稳定的,事实上,也确实如此,这个关键字的作用就是告诉编译器,只要是被此关键字修饰的变量都是易变的.不稳定的.那为什么是易变的呢?因为volatile所修饰的变量是直接存在于主内存中的,线程对变量的操作也是直接反映在主内存中,所以说其是易变的. 一.Java内存模型 Java内存模型规定所有的变量都是存在主存当中(类似于前面说的物理…
首先这两种方式都是延迟初始化机制,就是当要用到的时候再去初始化. 但是Effective Java书中说过:除非绝对必要,否则就不要这么做. 1. DCL (double checked locking)双重检查: 如果出于性能的考虑而需要对实例域(注意这个属性并没有被static修饰)使用延迟初始化,就使用双重检查模式 public class Singleton { private volatile Singleton uniqueInstance; private Singleton(){…
尊重原创: http://gstarwd.iteye.com/blog/692937 2004 年 5 月 01 日 所有的编程语言都有一些共用的习语.了解和使用一些习语很有用,程序员们花费宝贵的时间来创建.学习和实现这些习语.问题是,稍后经过证明,一些习 语并不完全如其所声称的那样,或者仅仅是与描述的功能不符.在 Java 编程语言中,双重检查锁定就是这样的一个绝不应该使用的习语.在本文中,Peter Haggar 介绍了双重检查锁定习语的渊源,开发它的原因和它失效的原因.  编辑注 :本文在…
双重检查加锁机制(并发insert情况下数据重复插入问题的解决方案) c#中单例模式和双重检查锁 转:https://blog.csdn.net/zhongliangtang/article/details/81564749…
单例模式是程序设计中经常用到的,简单便捷的设计模式,也是很多程序猿对设计模式入门的第一节课.其中最经典的一种写法是: class Singleton { private volatile static Singleton instance;//volatile关键字防止指令重排 private Singleton(){} public static Singleton getInstance() { if ( instance == null ) { //一重判断 synchronized (S…
volatile是java中的一个类型修饰符.它是被设计用来修饰被不同线程访问和修改的变量.如果不加入volatile,基本上会导致这样的结果:要么无法编写多线程程序,要么编译器 失去大量优化的机会. 1,可见性     可见性指的是在一个线程中对该变量的修改会马上由工作内存(Work Memory)写回主内存(Main Memory),所以会马上反应在其它线程的读取操作中.顺便一提,工作内存和主内存可以近似理解为实际电脑中的高速缓存和主存,工作内存是线程独享的,主存是线程共享的. 2,禁止指令…
在只有双重检查锁,没有volatile的懒加载单例模式中,由于指令重排序的问题,我确实不会拿到两个不同的单例了,但我会拿到"半个"单例. 而发挥神奇作用的volatile,可以当之无愧的被称为Java并发编程中"出现频率最高的关键字",常用于保持内存可见性和防止指令重排序. 保持内存可见性 内存可见性(Memory Visibility):所有线程都能看到共享内存的最新状态. 失效数据 以下是一个简单的可变整数类: public class MutableInteg…
Java中的volatile关键字的功能 volatile是java中的一个类型修饰符.它是被设计用来修饰被不同线程访问和修改的变量.如果不加入volatile,基本上会导致这样的结果:要么无法编写多线程程序,要么编译器 失去大量优化的机会. 1,可见性 可见性指的是在一个线程中对该变量的修改会马上由工作内存(Work Memory)写回主内存(Main Memory),所以会马上反应在其它线程的读取操作中.顺便一提,工作内存和主内存可以近似理解为实际电脑中的高速缓存和主存,工作内存是线程独享的…
在只有双重检查锁,没有volatile的懒加载单例模式中,由于指令重排序的问题,我确实不会拿到两个不同的单例了,但我会拿到“半个”单例. 而发挥神奇作用的volatile,可以当之无愧的被称为Java并发编程中“出现频率最高的关键字”,常用于保持内存可见性(随时见到的都是最新值)和防止指令重排序. 保持内存可见性 内存可见性(Memory Visibility):所有线程都能看到共享内存的最新状态. 失效数据 以下是一个简单的可变整数类: public class MutableInteger…
原子操作:不可被中断的操作.要么全执行,要么全不执行. 现代CPU读取内存,通过读取缓存再写入主存.先去主存读--->写入缓存---->运行线程--->写入缓存---->写入主存 多cpu时会出现缓存一致性和总线锁的问题. 只有简单的读取,赋值操作,即一步完成的操作才是原子操作. volatile,synchronized,lock 能保证可见性, volatile保证修改的值立即更新到主存,synchronized和lock保证同一时刻只有一个线程操作变量,在锁被释放前会将新值写…
volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果.在Java 5之后,volatile关键字才得以重获生机. volatile关键字虽然从字面上理解起来比较简单,但是要用好不是一件容易的事情.由于volatile关键字是与Java的内存模型有关的,因此在讲述volatile关键之前,我们先来了解一下与内存模型相关的概念和知识,然后分析了volatile关键字的实现原理,最后给出了几个使用vola…