java并发——java内存模型
并发编程两个关键问题:
线程之间如何同步和线程之间如何通信,java采用共享内存模型进行同步和通信
java内存的抽象结构
在java中,所有实例域、静态域、和数组元素都存储在堆内存中,堆内存在线程之间共享,局部变量、方法定义参数等不共享,他们不存在内存可见性问题,也不收到内存模型的影响
JMM通过控制主内存和每个线程的本地存储之间的交互来为java程序提供内存可见性
happens-before
我们使用happens-before的概念来阐述操作之间的内存可见性,在JMM中,如果一个操作执行的结果需要对另一个操作可见,那么这两个操作之间必须存在happens-before关系,这里提到的两个操作既可以在一个线程内,也可以是不同的线程之间。
happens-before规则如下:
- 一个线程中的每个操作,happens-before与该线程中的任意后续操作
- 对于一个锁的解锁,happens-before于这个锁的加锁
- 对于一个volatile的写,happens-before于他的读
- 具有传递性
- 如果线程A执行ThreadB.start(),那么线程A的ThreadB .start()规则happens-before于线程B中的任何操作
- 如果线程A执行ThreadB.join(),那么线程B 的任意操作happens-before于线程A从ThreadBare.join()操作返回成功
编译器和处理器会对操作顺序进行重排序,但是不会改变存在数据依赖性的两个操作的顺序。
as-if-serial规则:不管怎么重排序,(单线程)程序的执行结果都不会改变。这个规则为编写单线程的程序员提供了一个幻觉,单线程的程序是按照程序的顺序来执行的
volatile变量的内存语义
volatile变量自身具有以下的特性:
可见性:对于一个volatile变量的读,总能够看到(任意线程)对于这个volatile变量的最后的写入
原子性:对于任意单个volatile变量的读、写具有原子性,但是类似于volatile++这种符合操作不具有原子性
volatile写的内存语义如下:
当写一个volatile变量时候,JMM会把该线程对应的本地内存中的共享变量值刷新到主内存中
volatile读的内存语义如下:
当读一个volatile变量时候,JMM会把该线程对应的本地内存设置为无效,线程接下来会去7 主内存读取共享变量
锁的内存语义
锁释放和volatile写有相同的内存语义,锁获取与volatile读有相同的语义
concurrent包的实现
首先是声明共享变量为volatile
然后使用CAS原子条件来更新实现线程之间的同步
同时配合volatile读写和CAS所具有的volatile读写之间的内存语义来实现线程之间的通信