volatile 原理
volatile :关键字可以保证变量的可见性,禁止指令重排,但是不保证原子性;
synchronized 也可以保证变量的可见性,可以保证原子性;
写屏障(sfence):保证在该屏障之前的,对共享变量的改动,都同步到主存中;
读屏障(lfence):保证在该屏障之后,对共享变量的读取,加载的是主存中最新的数据;
JMM内存模型
JMM 即 Java Memory Model,它定义了主存、工作内存抽象概念,底层对应着 CPU 寄存器、缓存、硬件内存、CUP 指令优化等;JMM控制 Java 线程之间的通信,JMM 决定了一个线程对共享变量何时对另外一个线程可见。
JMM 体现在一下几个方面:
- 原子性:保证指令不会受到线程上下文切换的影响;
- 可见性:保证指令不会受到 CPU 缓存的影响;
-
JMM解决的问题
线程之间同步:控制不同线程间操作的顺序性;
- 线程之间通信
- 共享内存:线程之间共享程序的公共状态,通过读写内存的公共状态进行隐式通信;
- 消息传递:线程之间必须通过发送消息来显式进行通信;
happens-before 规则
happens-before的概念最初由Leslie Lamport在其一篇影响深远的论文(《Time,Clocks and the Ordering of Events in a Distributed System》)中提出。
JSR-133使用happens-before的概念来指定两个操作之间的执行顺序。
由于这两个操作可以在一个线程之内,也可以是在不同线程之间。因此,JMM可以通过happens-before关系向程序员提供跨线程的内存可见性保证(如果A线程的写操作a与B线程的读操作b之间存在happens-before关系,尽管a操作和b操作在不同的线程中执行,但JMM向程序员保证a操作将对b操作可见)。
具体规则:
- 程序的顺序规则:一个线程中的每个操作,happens-before于该线程中的任意后续操作。
- 监视器锁规则:对一个锁的解锁,happens-before于随后对这个锁的加锁。
- volatile变量规则:对一个volatile域的写,happens-before于任意后续对这个volatile域的读。
- 传递性:如果A happens-before B,且B happens-before C,那么A happens-before C。
- start()规则:如果线程A执行操作ThreadB.start()(启动线程B),那么A线程的ThreadB.start()操作happens-before于线程B中的任意操作。
- join()规则:如果线程A执行操作ThreadB.join()并成功返回,那么线程B中的任意操作happens-before于线程A从ThreadB.join()操作成功返回。
- 程序中断规则:对线程interrupted()方法的调用先行于被中断线程的代码检测到中断时间的发生。
对象finalize规则:一个对象的初始化完成(构造函数执行结束)先行于发生它的finalize()方法的开始。
重排序
什么是重排序:重排序是指编译器和处理器为了优化程序性能而针对指令序列进行指令重排序;
保证数据依赖性:保证重排序不会改变存在数据依赖的关系;
- as-if-serial :保证在单线程的情况下,指令重排不会导致内存可见性问题;