一文详解Java内存模型与原子性、可见性、有序性

file

1、Java内存模型

Java Memory Modle,简称 JMM,中文名称 Java内存模型,它是一个抽象的概念,用来描述或者规范访问内存变量的方式。由于各中计算机的操做系统和硬件不一样,方式机制也可能不一样,Java内存模型用于屏蔽(适配)各类差别,以此来达到访问各个平台的一致的效果。这也是Java夸平台的重要缘由之一。java

主内存: Java内存规定了全部变量都存储在主内存(Main Memory)中,各个线程又有本身的本地内存(工做内存),本地内存保存着主内存中部分变量。具体访问方式以下:面试

file

  • lock加锁:为了保证访问主内存变量的线程安全性,在访问前通常会加锁处理;
  • read读:从主内存中读取一个变量到工做内存;
  • load加载:把read读到的变量加载到工做内存的变量副本中;
  • use使用:此时线程可使用其工做内存中的变量了;
  • assign赋值:将处理后的变量赋值给工做内存中的变量;
  • store存储:将工做内存中的变量存储到主内存中,以新建new 一个新变量的方式存储;
  • write写:将store存在的新变量的引用赋值给被处理的变量;
  • unload解锁:全部的工做作完,最后解锁释放资源。

2、Java内存模型的三大特性

一、原子性(Atomicity)spring

这里的原子性如同数据库事务中是原子性,一个或多个操做要么全执行成功要么全执行失败(全不执行)。数据库

int a = 1;
a++;
double b = 1.5;

Java内存模型只保证单一的操做具备原子性,好比上面的 int a = 1; 是一个单子的操做,因此具备原子性。设计模式

而 a++ 操做在底层会分为三个操做:安全

1)、读取a的值给临时变量;网络

2)、临时变量a的值加1操做;数据结构

3)、将加操做后的值赋值给a。多线程

每一个操做都是原子的,但Java内存模型在多线程下并不能保证多操做具备总体原子性,由于它也不知道这个总体内有多少操做,用户想要达到多操做具备总体原子性,须要对响应的代码块作同步(synchronous)处理,好比使用 有锁的synchronized 或 无锁的CAS。框架

二、可见性(Visibility)

这里的可见性是内存可见性。

file

如上图,线程1和线程2在未同步的状况下对共享内存(主内存)中的变量进行访问,好比两个线程的操做都是对变量a进行加1操做。

假设线程1首先获取主内存中变量a的值,随后线程2又获取了主内存变量a的值,此时它们工做内存中a的值都是1,它们各自将a的值加1操做,而后assign至工做内存,工做内存中变量a的值都是2,而后两个线程又将值刷新到主内存,最后的结果是主内存中变量a的值是2。

虽然总体对a的值加1操做作了两次操做,但因为线程间的操做是互相隔离的,默认状况下没法感知内存变量的值在随后的变化,也就没法访问内存中最新的变量值,这就是内存可行性的问题。

如何解决内存可见性的问题?

  • 对进入临界区的线程作同步处理(好比 synchronized),同一时刻仅有一个线程可以访问临界区的资源;
  • 使用 volatile 关键字保证内存可见性,它能保证访问临界区资源的全部线程总能看到共享资源的最新值;
  • CAS无锁化。

三、有序性(Ordering)

线程内的全部操做都是有序的,既程序执行的顺序按照代码的前后顺序执行。好比下面的示例:

int a = 1;
int b = 2;
int c = a + b;

线程内程序会先执行 int a = 1; ,而后执行 int b = 2; 最后执行int c = a + b;。

文源网络,仅供学习之用,若有侵权请联系删除。

我将面试题和答案都整理成了PDF文档,还有一套学习资料,涵盖Java虚拟机、spring框架、Java线程、数据结构、设计模式等等,但不只限于此。

关注公众号【java圈子】获取资料,还有优质文章每日送达。

file

相关文章
相关标签/搜索