线程之间的通信机制:共享内存和消息传递
在共享内存的并发模型中,线程之间共享程序的公共状态,通过写-读内存中的公共状态进行隐式通信。在消息传递的并发模型中,线程之间没有公共状态,线程之间必须通过发送消息来显式进行通信。
JAVA采用共享内存的并发模型

  1. java中,所有实例域、静态域、数组元素都存储在堆内存中,堆内存在线程之间共享。
  2. java 共享内存 加信号量 java实现共享内存_重排序

  3. java线程之间的通信又java内存模型(JMM)控制,JMM决定了一个线程对共享变量的写入何时对另一个线程可见。
    线程之间的共享变量存储在主内存中,每个线程都有一个私有的本地内存,本地内存存储了该线程以读/写共享变量的副本。
    从上图看出,线程A和线程B要通信的话,需要经历一下步骤;
  4. 线程A把本地内存A中更新过的共享变量刷新到主内存中。
  5. 线程B到主内存读取线程A之前已更新过的共享变量
    JMM通过控制主内存与每个线程的本地内存之间的交互,来为java程序提供可见性保证。
    重排序
  6. java 共享内存 加信号量 java实现共享内存_编译器_02

1:编译器优化重排序:编译器在不改变单线程程序语义的前提下,可以重排序

2:指令级并行的重排序:处理器在不存在数据依赖性的前提下,可以改变语句对应机器指令的执行顺序

3:内存系统的重排序:由于处理器使用缓存和读写缓存区,这使得加载和存储操作看起来的无序的

对于编译器,JMM的编译器重排序规则会禁止特定类型的编译器重排序。

对于处理器重排序,JMM的处理器重排序规则会要求编译器在生成指令前,插入特定类型的

内存屏障指令,通过内存屏障指令来禁止特定类型的处理器重排序。、

内存屏障有四类,

java 共享内存 加信号量 java实现共享内存_重排序_03

在JMM中,如果一个操作执行的结果需要对另外一个操作可见,那么这两个操作之间必须存在happens-before关系.

如果两个操作访问同一个变量,其一个为写,那么这两个操作之间就存在数据依赖性。

as-if-serial 语义:不管怎么重排序,单线程的执行结果都不能被改变。遵守这个协议,处理器就不会对存在数据依赖性的操作做重排序。

java 共享内存 加信号量 java实现共享内存_编译器_04


上面StoreStore 将保障上面所有的普通写在volatile写之前刷新到主内存。

java 共享内存 加信号量 java实现共享内存_共享变量_05


LoadLoad屏障用来禁止处理器把上面的volatile读与下面的普通读重排序。
LoadStore屏障用来禁止处理器把上面voaltile读与下面的普通写重排序。