JAVA 支持并发线程操作,其内存模型也不是简单的所有线程共同操作内存。在 JVM 中,每个线程都有自己的内存空间,线程的操作都在自己的内存空间中执行,必要时再同步到公共内存,让其它的线程看见。
volatile
volatile 关键字保证了各个线程都能实时性地看到某个变量的值,它是怎么做到的呢?
被 volatile 修饰的变量具有特殊性,欲更改该变量的值的线程必须先从公共内存中获取该变量的值,存入自己的空间进行操作,改完了还必须“立刻”同步回公共内存,以便其它线程知道变量值被改变,这维护了变量的一致性。
volatiel 还能保证指令不会被“重排序”,volatile 修饰了哪个变量,该变量的赋值等操作的次序就不能被编译器优化。
但 volatile 并不能保证原子性。虽然各个线程都能看到变量值的变化,但有可能有两个线程都修改该变量的值,其中任何一个线程的操作都有可能不是原子操作。
原子性
原子性有 synchronized 来保证,被 synchronized 修饰的方法,在一段时间内只能由一个线程执行。
可见性
可见性是指,一个变量的值被一个线程改变后,其它线程能够立即知晓,而不会导致彼此线程间不知道对方做了什么。
该性质明显可以由 volatile 来保证,另外,synchronized也能保证可见性,为什么呢?
被 synchronized 修饰的变量在被一个线程修改时,别的线程不能碰该变量,当轮到别的线程时,别的线程自然就看到变量被前一个线程修改了。
有序性
volatile 和 synchronized 都能保证有序性。
volatile 阻止指令的重排序优化,而 synchronized 使得线程们只能一个个排着队来执行某段代码。