zoukankan      html  css  js  c++  java
  • jvm的可见性的理解

    同步包括两方面的含义: 独占性和可见性。

    很多人仅仅理解了独占性,而忽略了可见性。

    根据Java Language Specification中的说明, jvm系统中存在一个主内存(Main Memory或Java Heap Memory),Java中所有变量都储存在主存中,对于所有线程都是共享的。

    每条线程都有自己的工作内存(Working Memory),工作内存中保存的是主存中某些变量的拷贝,线程对所有变量的操作都是在工作内存中进行,线程之间无法相互直接访问,变量传递均需要通过主存完成。

    一种常见的错误是,只有在写入共享变量时才需要同步,而读取的时候并不需要同步。

     

    publicclass GetAndSet {

     

       privateint i;

     

       publicint getI() {

         returni;

       }

     

       publicsynchronized void setI(int i) {

         this.i = i;

       }

      

      

    }

    在多线程环境中,仅从独占性上分析,上述程序根本不存在任何问题。

    问题出在了可见性上,

    即,如果调用

    在线程A中:setI(10);

    然后在线程B中:getI();

    得到的很可能并非10,这个我们想要的答案。

    这是因为并没有什么保证,在线程A设置的I,在线程B中可以立马看到当前值。

    Java内存模型就是为了解决可见性的问题。

    JMM规定了JVM必须遵循的一组最小保证,这组保证规定了对变量的写入操作在何时将对于其他线程是可见的。

    这组保证就是Happen-Before 规则。

    happen before规则: 
    Each action in a thread happens before everyaction in that thread that comes later in the program's order. 
    An unlock on a monitor happens before everysubsequent lock on that same monitor. 
    A write to a volatile field happens before everysubsequent read of that same volatile. 
    A call to start() on a thread happens before anyactions in the started thread. 
    All actions in a thread happen before any otherthread successfully returns from a join() on that thread. 

    happen before翻译过来就是: 
    程序顺序规则:一个线程中的每个操作,happens- before 于该线程中的任意后续操作。 
    监视器锁规则:对一个监视器锁的解锁,happens- before 于随后对这个监视器锁的加锁。 
    volatile变量规则:对一个volatile域的写,happens- before 于任意后续对这个volatile域的读。 
    传递性:如果Ahappens- before B,且B happens- before C,那么A happens- before C。 
    Thread.start()的调用会happens-before于启动线程里面的动作。 
    Thread中的所有动作都happens-before于其他线程从Thread.join中成功返回。

    Happen-Before 规则是由JVM提供的,因此无论有没有“同步协助(synchronized,lock ,volatile,final)”,程序执行时都必须遵守这些规则, 只不过这些规则中的大部分和同步协助有关系。

    注意:第一条程序顺序规则,按字面意思的话,在同一个线程中所有语句的执行过程,必须按照程序流的先后去执行。不可能有任何重排序的可能。

    实际情况并非如此,在同一个线程中,只有有数据相关的操作才不会被重排序,而没有任何关系的操作是可以被编译器发现,并进行适当重排的。

    如:inti =10; --------------a

    intj =1;----------------------b

     i =i+1;----------------------c

    虽然 a  hanppen  before b, 可在真实执行的时候,b有可能会在a前执行。因为该线程根本无法感知这种顺序的变化。

    可是,a 不可能在c后面执行,因为这个线程本身可以感知这个顺序的变化。

  • 相关阅读:
    设计模式-外观模式
    发生死锁怎么办
    设计模式-工厂模式
    设计模式-模板方法
    设计模式-命令模式(Command)
    设计模式-单例模式
    设计模式-装饰器模式
    CQRS之旅——旅程8(后记:经验教训)
    CQRS之旅——旅程7(增加弹性和优化性能)
    CQRS之旅——旅程6(我们系统的版本管理)
  • 原文地址:https://www.cnblogs.com/LvLoveYuForever/p/5900653.html
Copyright © 2011-2022 走看看