JMM¶
JVM运行程序的实体是线程,而每个线程创建时JVM都会为其创建一个工作内存(有些地方称为栈空间),用于存储线程私有的数据,而Java内存模型中规定所有变量都存储在主内存,主内存是共享内存区域,所有线程都可以访问,但线程对变量的操作(读取赋值等)必须在工作内存中进行,首先要将变量从主内存拷贝的自己的工作内存空间,然后对变量进行操作,操作完成后再将变量写回主内存,不能直接操作主内存中的变量,工作内存中存储着主内存中的变量副本拷贝。
主内存¶
主要存储的是Java实例对象,所有线程创建的实例对象都存放在主内存中,不管该实例对象是成员变量还是方法中的本地变量(也称局部变量),当然也包括了共享的类信息、常量、静态变量。由于是共享数据区域,多条线程对同一个变量进行访问可能会发现线程安全问题。
主内存中的实例对象可以被多线程共享,倘若两个线程同时调用了同一个对象的同一个方法,那么两条线程会将要操作的数据拷贝一份到自己的工作内存中,执行完成操作后才刷新到主内存
工作内存¶
主要存储当前方法的所有本地变量信息(工作内存中存储着主内存中的变量副本拷贝),每个线程只能访问自己的工作内存,即线程中的本地变量对其它线程是不可见的。
原则¶
- 原子性:使用synchronized关键字或者重入锁(ReentrantLock)保证程序执行的原子性
- 可见性:synchronized 或者 volatile
- 有序性:volatile
happens-before¶
- 按照代码顺序执行
- 加锁的动作必须在解锁动作之后
- volatile变量在每次被线程访问时,都强迫从主内存中读该变量的值,不同的线程总是能够看到该变量的最新值
- A先于B ,B先于C 那么A必然先于C
- 线程的所有操作先于线程的终结
volatile保证可见性和有序性
synchronized保证可见性和有序性; 通过**管程(Monitor)*保证一组动作的*原子性
final通过禁止在构造函数初始化和给 final 字段赋值这两个动作的重排序,保证可见性(如果 this 引用逃逸就不好说可见性了)