Java内存模型
Java内存模型的主要目的是定义程序中各种变量的访问规则,即关注在JVM中把变量值存储到内存和从内存中取出变量值的底层细节。
此处的变量不包括局部变量和方法变量,因为这些变量是线程私有的,不会被共享,自然不会存在竞争问题。
Java内存模型规定了所有的变量都存储在主内存(Main Memory)中。每个线程都有自己的工作内存(Working Memory),线程的工作内存中保存了被该线程使用的变量的主内存副本,线程对变量的所有操作(读写、赋值等)都必须在工作内存中进行,而不能直接读写主内存中的数据。不同的线程之间也无法直接访问对方工作内存中的变量,线程间变量的传递均需要通过主内存来完成。

volatile关键字
当一个变量被定义为volatile之后,它将具备两个特性:
- 保证该变量对所有线程的可见性,这里的可见性是指当一个线程修改了该变量的值,新值对于其他线程是可以立即得知的。而普通变量做不到这一点,普通变量的值在线程间传递时均需要通过主内存来完成。
- 使用volatile关键字将禁止指令重排序优化,普通的变量仅会保证在该方法的执行过程中所有以来赋值结果的地方都能获取到正确的结果,而不能保证变量赋值操作的顺序于程序代码中的执行顺序一致。
volatile关键字并不能保证变量在多线程情况下是线程安全的。volatile变量在各线程的工作内存中是不存在一致性问题的(从物理存储角度看,各线程的工作内存中volatile变量也可以存在不一致的情况,但由于每次使用之前都要先刷新,执行引擎看不到不一致的情况,因此认为不存在一致性问题),但Java里的运算操作符并非原子操作,这就会导致volatile变量的运算在并发时也是线程不安全的。
由于volatile变量只能保证可见性,在不符合一下两条规则的运算场景中,仍然要通过锁(sychronized、等)来保证原子性:
- 运算结果并不依赖变量的当前值,或能够确保只有单一的线程修改变量的值。
- 变量不需要与其他的状态变量共同参与不变约束。
原子性、可见性、有序性
Java内存模型是围绕着在并发过程中如何处理原子性、可见性、有序性三个特征建立起来的
原子性
由Java内存模型来直接保证的原子性变量操作:read、load、assign、use、store、write。基本数据类型(long、double除外)的访问、读写都是具备原子性的。
可见性
可见性是指当一个线程修改了共享变量的值时,其他线程能够立即得知这个修改。Java内存模型是通过在变量修改后将新值同步回主内存,在变量读取前从主内存刷新变量值,这种依赖主内存作为传递媒介的方式来实现可见性的,无论是普通变量还是volatile变量都是如此。普通变量和vloatile变量的区别是,volatile的特殊规则保证了新值能立即同步到主内存,以及每次使用前立即从主内存刷新。因此volatile保证了多线程操作时变量的可见性,而普通变量不能保证。
除了volatile之外,还有两个关键字能实现可见性,分别是synchronized和final。
同步块的可见性是由“对一个变量执行unlock操作之前,必须先把此变量同步回主内存中(执行store、write操作)”这条规则获得的
final关键字的可见性指:被final修饰的字段在构造器中一旦被初始化完成,且构造器没有把“this”的引用传递出去,那么其他线程就能看到final字段的值。
有序性
如果在本线程内观察,所有的操作都是有序的,如果在一个线程中观察另一个线程,所有的操作都是无序的。
前半句是指:线程内表现为串行的语义。
后半句是指:指令重排序现象和工作内存与主内存同步延迟现象

浙公网安备 33010602011771号