Java内存模型
2018-02-22 本文已影响10人
34sir
如果对内存模型没有一个基本的了解,建议先看有关并发编程
书归正传,以大家都已经熟悉了内存模型中的原子性,可见性,有序性为前提,我们来聊一聊Java对这三者提供了哪些保证
原子性
分析一下下面的这段代码,看看哪些是原子性操作
x = 1; //语句1
y = x; //语句2
x++; //语句3
x = x + 1; //语句4
答案:只有语句1才是原子性操作
下面我们分析一下:
语句1:单纯的将数值1赋给x,也就是直接将1写入到工作内存中,一个步骤,显然满足原子性
语句2:先读取x的值,再将x的值写入工作内存,两个步骤,显然不满足原子性
语句3:先读取x的值,然后进行加一操作,然后写入工作内存,三个步骤,显然不满足原子性
语句4:同语句三,有三个步骤,不满足原子性
对于原子性的判断做个总结:
只有简单的读取、赋值(而且必须是将数值赋值给某个变量,变量之间的相互赋值不是原子操作)才是原子操作
如果要实现更大范围操作的原子性,可以通过synchronized和Lock来实现
可见性
Java保证可见性的,两种方式:
- volatile
当一个共享变量被volatile修饰时,它会保证修改的值会立即被更新到主存,当有其他线程需要读取时,它会去主存中读取新值 - synchronized和Lock
synchronized和Lock能保证同一时刻只有一个线程获取锁然后执行同步代码,并且在释放锁之前会将对变量的修改刷新到主存当中,所以,可以保证可见性
有序性
Java保证有序性的两种方式
- volatile
可以保证一定的有序性,具体的原理我会的单独分一篇来分析volatile - synchronized和Lock
保证每个时刻是有一个线程执行同步代码,相当于是让线程顺序执行同步代码,这样显然就具备有序性
关于有序性,Java中默写情况下是默认具备有序性的,这个通常被叫做happens-before
原则,满足此原则的就能保证有序性
下面介绍一下happens-before
(先行发生)原则:
- 次序规则:同一个线程中,按照代码的顺序,书写在前面的操作优先发生于书写在后面的操作
这个描述其实不太准确,因为有指令重排,这个规则的意思其实是:即使发生了指令重排,我们也可以当做按照代码顺序执行来理解,因为结果是相同的 - 锁定规则:一个unLock操作先行发生于后面对同一个锁的lock操作
锁定状态,解锁在加锁之前 -
volatile
规则:对一个变量的写操作先行发生于后面对这个变量的读操作 - 传递原则:A先发生于B,并且B先发生于C,那么A先发生于C