zoukankan      html  css  js  c++  java
  • DCL单例为什么要加Volatile

    拿一个对象创建赋值来说

    class T{
      int  elem = 1;
    }
    
    T t = new T();

    上段代码转换成汇编码为:

    0  new  #2 <T>
    3  dup
    4  invokespecial  #3  <T.<init>>
    7  astore_1
    8  return 

    从汇编码中可以看出,0行为对象开辟了一个内存空间,该内存的成员区包含整形变量elem,值初始为0(如果是引用或者指针变量则为空)。3行dup指令是在栈中复制一个对象的引用(在new的时候该栈中已经存在一个,执行dup后也就是两个了),第4行执行初始化,为对象成员变量赋值,这个时候会消耗一个引用并将它从栈中pop掉,这也是为什么要dup的原因。7行指令是将栈中的引用赋值给对象t,并在栈中pop掉该引用。8然后return。这个是整个汇编语言按源代码执行得过程。

    但是cpu本质上得乱序执行,可能造成指令得重排,特别是在初始化对象指令上花费时间较多,可能进行了如下重排:

    0  new  #2 <T>
    3  dup
    7  astore_1
    4  invokespecial  #3  <T.<init>>
    8  return 

    指令第7行可能在cpu执行是与第4行重排,那么当线程一从0开始执行,执行到第7行得时候将未初始化得对象得引用赋值给t,如果线程一挂起,线程二发现t的引用不为空在执行下面代码:if (t != null)  xxxx->使用了半初始化得对象。会造成后续程序出错。所以用volatile来禁止指令重排来保证单例线程安全。

  • 相关阅读:
    Java:类加载器(ClassLoader)
    Java 并发:Executor
    Java 并发:线程中断-interrupt
    UNIX IPC: POSIX 消息队列 与 信号
    Java与C++区别:重载(Overloading)
    UNIX IPC: POSIX 消息队列
    PAT 1078. Hashing
    PAT 1032. Sharing
    回顾经典问题算法:LIS, LCS-(DP类别)
    url编码模块
  • 原文地址:https://www.cnblogs.com/lhdeng1991/p/12922451.html
Copyright © 2011-2022 走看看