1、java内存模型的基础
在多线程编程中,线程之间的通信机制有两种:共享内存和消息传递。在共享内存的并发模型中,线程之间共享程序的公共状态,通过写-读内存中的公共状态进行隐式通信;在消息传递的并发模型中,线程之间没有公共状态,线程之间必须通过消息进行显式通信。
java线程之间的通信通过java内存模型(简称JMM)控制。JMM定义了线程和主内存之间的抽象关系:线程之间的共享变量存储在主内存中,每个线程都有一个私有的本地内存,本地内存中存储了该线程以读/写共享变量的副本。本地内存并不真实存在,只是一个抽象概念。
2、happens-before原则
在JMM中,如果一个操作的执行结果需要对另一个操作可见,那么这两个操作之间必须要存在happens-before关系。主要有以下几种:
1)程序顺序规则:一个线程中的每个操作,happens-before于该线程中的任意后续操作。
2)监视器规则:对一个锁的解锁,happens-before于随后对这个锁的加锁。
3)volatile变量规则:对一个volatile域的写,happens-before于任意后续对这个volatile域的读。
4)传递性:如果A happens-before B,且B happens-before C,那么A happens-before C。
5)start()规则:如果线程A执行操作ThreadB.start(),那么A线程中的ThreadB.start()操作happens-before于线程B中的任意操作。
6)join()规则:如果线程A执行操作ThreadB.join()并成功返回,那么线程B中的任意操作happens-before于线程A从ThreadB.join()操作成功返回。
在这里,与程序员相关的只有1)2)3)4)这四条。
3、as-if-serial语义
在执行程序的过程中,编译器和处理器为了优化程序性能,会对指令序列进行重新排序。as-if-serial的意思就是,不管怎么重排序,单线程程序的执行结果不会发生改变。
4、volatile的内存语义
volatile变量具有以下特性:
1)可见性:对一个volatile变量的读,总是能看到任意线程对这个volatile变量最后的写入。
2)原子性:对任意单个volatile变量的读/写具有原子性,而对于类似volatile++这样自增操作不具有原子性。
3)禁止指令重排序
5、内存之间的交互操作
lock(锁定):作用于主内存的变量,它把一个变量标识为一条线程独占的状态。
unlock(解锁):作用于主内存的变量,它把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定。
read(读取):作用于主内存的变量,它把一个变量的值从主内存传输到线程的工作内存中,以便虽有的load动作使用。
load(载入):作用于工作内存中的变量,它把read操作从主内存中得到的变量值放入工作内存的变量副本中。
use(使用):作用于工作内存中的变量,它把工作内存中的一个变量的值传递给执行引擎,每当虚拟机遇到一个需要使用到变量的值的字节码指令时,将会执行这个操作。
assign(赋值):作用于工作内存中的变量,它把一个从执行引擎接收到的值赋值给工作内存的变量,每当虚拟机遇到一个给变量赋值的字节码指令时执行这个操作。
store(存储):作用于工作内存中的变量,它把工作内存中的一个变量的值传递到主内存中,以便随后的write操作使用。
write(写入):作用于主内存中的变量,它把store操作从工作内存中得到的变量的值放入到主内存的变量中。
read and load 从主内存复制变量到当前工作内存
use and assign 执行代码,改变共享变量值
store and wirte 把工作内存数据刷新到主存
这些操作并不是原子性,也就是read and load之后,如果主内存变量发生修改之后,线程工作内存中的值由于已经加载,不能产生相应的变化,所以计算出来的结果会和预期不一致。对于volatile修饰的变量,JVM虚拟机只能保证从主内存加载到线程工作内存的值是最新的。
待续。。。