Java内存模型详解

内存模型 (memory model) java

内存模型描述的是程序中各变量(实例域、静态域和数组元素)之间的关系,以及在实际计算机系统中将变量存储到内存和从内存取出变量这样的低层细节. 数组

不一样平台间的处理器架构将直接影响内存模型的结构. 缓存

在C或C++中, 能够利用不一样操做平台下的内存模型来编写并发程序. 可是, 这带给开发人员的是, 更高的学习成本.相比之下, Java利用了自身虚拟机的优点, 使内存模型不束缚于具体的处理器架构, 经过Java内存模型真正实现了跨平台.(针对hotspot jvm, jrockit等不一样的jvm, 内存模型也会不相同) 多线程

内存模型的特征: 架构

a, Visibility 可视性 (多核,多线程间数据的共享) 并发

b, Ordering 有序性 (对内存进行的操做应该是有序的) app


Java内存模型 ( java memory model ) jvm

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

每条线程都有本身的工做内存(Working Memory),工做内存中保存的是主存中某些变量的拷贝,线程对全部变量的操做都是在工做内存中进行,线程之间没法相互直接访问,变量传递均须要经过主存完成。 学习

Java内存模型

其中, 工做内存里的变量, 在多核处理器下, 将大部分储存于处理器高速缓存中, 高速缓存在不通过内存时, 也是不可见的.

jmm怎么体现可视性(Visibility) ?

在jmm中, 经过并发线程修改变量值, 必须将线程变量同步回主存后, 其余线程才能访问到.

jmm怎么体现有序性(Ordering) ?

经过Java提供的同步机制或volatile关键字, 来保证内存的访问顺序.

缓存一致性(cache coherency

什么是缓存一致性?

它是一种管理多处理器系统的高速缓存区结构,其能够保证数据在高速缓存区到内存的传输中不会丢失或重复。(来自wikipedia)

举例理解:

假若有一个处理器有一个更新了的变量值位于其缓存中,但尚未被写入主内存,这样别的处理器就可能会看不到这个更新的值.

解决缓存一致性的方法?

a, 顺序一致性模型:

要求某处理器对所改变的变量值当即进行传播, 并确保该值被全部处理器接受后, 才能继续执行其余指令.

b, 释放一致性模型: (相似jmm cache coherency)

容许处理器将改变的变量值延迟到释放锁时才进行传播.

Java内存模型的缓存一致性模型 - "happens-before ordering(先行发生排序)"

通常状况下的示例程序:

  • x = 0;  
    y = 0;   
    i = 0;   
    j = 0;     // thread A  
     
    y = 1;   
    x = 1;     // thread B   
    i = x;   
    j = y;
  • 在如上程序中, 若是线程A,B在无保障状况下运行, 那么i,j各会是什么值呢?

    答案是, 不肯定. (00,01,10,11都有可能出现),这里没有使用Java同步机制, 因此Java内存模型有序性和可视性都没法获得保障. happens-before ordering( 先行发生排序) 如何避免这种状况? 排序原则已经作到:

    a, 在程序顺序中, 线程中的每个操做, 发生在当前操做后面将要出现的每个操做以前.

    b, 对象监视器的解锁发生在等待获取对象锁的线程以前.

    c, 对volitile关键字修饰的变量写入操做, 发生在对该变量的读取以前.

    d, 对一个线程的 Thread.start() 调用 发生在启动的线程中的全部操做以前.

    e, 线程中的全部操做 发生在从这个线程的 Thread.join()成功返回的全部其余线程以前.

    为了实现 happends-before ordering原则, Java及JDK提供的工具:

    a, synchronized关键字

    b, volatile关键字

    c, final变量

    d, java.util.concurrent.locks包(since jdk 1.5)

    e, java.util.concurrent.atmoic包(since jdk 1.5)

    使用了happens-before ordering的例子:

    happens-before ordering的例子

    1) 获取对象监视器的锁(lock)

    (2) 清空工做内存数据, 从主存复制变量到当前工做内存, 即同步数据 (read and load)

    (3) 执行代码,改变共享变量值 (use and assign)

    (4) 将工做内存数据刷回主存 (store and write)

    (5) 释放对象监视器的锁 (unlock)

    注意: 其中4,5两步是同时进行的.

    这边最核心的就是第二步, 他同步了主内存,即前一个线程对变量改动的结果,能够被当前线程获知!(利用了happens-before ordering原则)

    对比以前的例子

    若是多个线程同时执行一段未经锁保护的代码段,颇有可能某条线程已经改动了变量的值,可是其余线程却没法看到这个改动,依然在旧的变量值上进行运算,最终致使不可预料的运算结果。

    相关文章
    相关标签/搜索