首页 > 学院 > 开发设计 > 正文

可见性

2019-11-08 03:02:06
字体:
来源:转载
供稿:网友

java内存模型

Java内存模型把Java虚拟机内部划分为线程栈和堆。每个线程都有自己的线程栈。如下图。

线程栈(Thread Stack):线程栈中存放了本地变量(线程执行过程中在方法内定义的变量,无论是基本类型还是引用类型)

堆(Heap):堆上则存放Java程序中创建的所有对象,一个对象包含的成员变量跟随对象一起存放在堆上

这里写图片描述

硬件内存架构

在多核CPU中,在同一时刻,可能每个CPU上边都同时分别跑着一个线程。

CPU缓存

寄存器:每个CPU都包含一系列的寄存器,它们是CPU内内存的基础(寄存器容量小,但访问速度远远大于内存)。缓存层:每个CPU可能还有一个CPU缓存层。实际上,绝大多数的现代CPU都有一定大小的缓存层。CPU访问缓存层的速度快于访问主存的速度,但通常比访问内部寄存器的速度还要慢一点。一些CPU还有多层缓存。

CPU读写与缓存的关系

读:当一个CPU需要读取主存时,它会将主存的部分读到CPU缓存中。它甚至可能将缓存中的部分内容读到它的内部寄存器中,然后在寄存器中执行操作。写:当CPU需要将结果写回到主存中去时,它会将内部寄存器的值刷新到缓存中,然后在某个时间点将值刷新回主存。

对于理解Java内存模型和内存交互原理,只需要知道CPU内部有一个缓存即可。如下图。

这里写图片描述

Java内存模型和硬件内存架构之间的桥接

硬件内存架构没有区分线程栈和堆。对于硬件,所有的线程栈和堆都分布在主内中。部分线程栈和堆可能有时候会出现在CPU缓存中和CPU内部的寄存器中。如下图。

这里写图片描述

产生问题

当对象和变量被存放在计算机中各种不同的内存区域中时,就可能会出现一些具体的问题。主要包括如下两个方面:

线程对共享变量修改的可见性当读,写和检查共享变量时出现竞争条件(race conditions)

共享对象可见性

对于共享对象,多个CPU上的线程可以同时将其读到CPU缓存中,然后修改这个对象。只要CPU缓存没有被刷新会主存,对象修改后的版本对跑在其它CPU上的线程都是不可见的。这种方式可能导致每个线程拥有这个共享对象的私有拷贝,每个拷贝停留在不同的CPU缓存中。如下图。 从本质上来讲,这是CPU的自身速度优化,使最新的Java对象不能及时地在多个线程相互可见(一个特性的优化往往会对另一个特性造成缺口)

这里写图片描述

竞争条件

如果两个线程同时将整型变量count读到各自的CPU缓存中,并且同时对其执行+1操作,最后再将count写会到内存中,最终count的值只会被+1,而不是+2,尽管执行了两次+1操作。 这里写图片描述


原文链接


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表