java并发——java内存模型

并发编程两个关键问题:

线程之间如何同步和线程之间如何通信,java采用共享内存模型进行同步和通信

java内存的抽象结构

在java中,所有实例域、静态域、和数组元素都存储在堆内存中,堆内存在线程之间共享,局部变量、方法定义参数等不共享,他们不存在内存可见性问题,也不收到内存模型的影响

java并发——java内存模型

JMM通过控制主内存和每个线程的本地存储之间的交互来为java程序提供内存可见性

happens-before

我们使用happens-before的概念来阐述操作之间的内存可见性,在JMM中,如果一个操作执行的结果需要对另一个操作可见,那么这两个操作之间必须存在happens-before关系,这里提到的两个操作既可以在一个线程内,也可以是不同的线程之间。

happens-before规则如下:

  1. 一个线程中的每个操作,happens-before与该线程中的任意后续操作
  2. 对于一个锁的解锁,happens-before于这个锁的加锁
  3. 对于一个volatile的写,happens-before于他的读
  4. 具有传递性
  5. 如果线程A执行ThreadB.start(),那么线程A的ThreadB .start()规则happens-before于线程B中的任何操作
  6. 如果线程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读写之间的内存语义来实现线程之间的通信