JVM内存模型

主内存、工作内存

  • 一条线程对应一个工作内存(专属高速缓冲)
  • 多个工作内存对应一个主内存
  • 通常情况下,主内存就是Java Heap,工作内存即虚拟机栈
  • 工作内存是主内存的数据的拷贝
  • 工作内存与主内存的交互是有一套规定的,有一套函数
  • 线程不会直接从主内存中获取数据,而是从自己的工作内存中拿数据,拿不到就从主内存中加载到工作内存,在从工作内存中获取

Volatile

想当年这东西可是背过的,但是又何曾理解他到底是干嘛的呢,借此机会来了解一哈。
记得当时看到的说法是用Volatile修饰的变量可以并发,不用怕同步问题,然而并不是这样的,但是他在某些情况下确实可以保证同步性,下面就来看看是咋整的。

Volatile修饰的变量有下面两个特点:
1. 可见性

一条线程修改了变量的值,其他使用它的线程能在使用它的时候获取到最新的值

volatile修饰的变量在值改变后会立刻向主内存写入,以至于别的线程在读这个变量的时候会读到最新的值,(在这里,线程每次使用这个变量的时候都必须从主内存中更新最新的值)但是这里说的改变是指该操作是具有原子性的情况下,不具有原子性的操作,例如i++,就算ivloatile修饰那在多个线程中对它进行读写也是不安全的

2. 禁止指令重排序

大家知道JVM是会对对字节码进行指令重排序优化的,也就是说,在一条线程内,我们的代码看起来是顺序执行的,然而实际上不是的,当上写文没有影响的时候,代码不一定是顺序执行的(先行的概念)。在多条线程中看,我们的代码并不是顺序执行的,,一个线程的代码会被其他线程插入,但是,在线程内看还是顺序的,这就是相对顺序。那么volatile修饰的变量,就禁止做这样的一种优化,在对volatile修饰的变量赋值时,JVM会加上一个lock指令,禁止后面的指令重排序到lock之前

Java内存模型欲实现

原子性

具有原子性的代码块执行时不会被打断
在并发中,我们的很多代码块是需要具有原子性的,JVM则提供了synchronized关键字让我们来实现代码原子性

可见性

一条线程修改了变量的值,其他使用它的线程能在使用它的时候获取到最新的值
上面说过,volatile可以实现可见性,当然synchronized也可以

有序性

线程之间的操作具有顺序,串行,线程之间的代码可以按照设想的顺序执行,不出现指令重排打乱顺序的情况
同样,synchronized可以实现有序性,lock住了那都具有原子性,也无法重排序,别人插不进来
Volatile也行,上面说过的,也是有lock的操作

先行发生

书中定义:先行发生是在Java内存模型中定义的两项操作之间的偏序关系,如果说操作A先行发生于操作B,那么操作A产生的影响能被操作B观察到,“影响”包括修改了内存中共享变量的值、调用了方法等

这是咋回事呢?来举个例子,假设一条线程中:操作A是i++;,操作B是i--;,若A先行发生于B,那么,从A到B一顿操作之后,i应该是原来的值,也就是说,B中观察到的i是A操作完之后的值,这样就叫做能被观察到。

从上面的例子来看,貌似,先行发生=先发生,事实上并不是,再来举个例子,还是在一条线程中,操作A是i++;,操作B是j++;,A写在B的前面,AB挨着写,那么A是先行发生于B的,但是!!A并不一定比B先发生,在这种情况下,即B中没有用到A中的值的情况下,B无法感知A操作产生的影响,所以,JVM会对指令进行重排序优化,可能B先发生于A,也有可能不变。由于B没用到A中的值,所以不存在观不观察,没有破坏先行发生的规则

你可能感兴趣的:(JVM内存模型)