一、可见性:

1、定义:线程对主内存的修改可以及时地被其他线程观察到;

2、导致共享变量在线程间不可见的可能性原因:

》线程交叉执行;

》重排序结合线程交叉执行;

》共享变量更新后的值没有在工作内存与主存间及时刷新;

3、不同解决方案对可见性的处理:

1)可见性——synchronized

JMM 关于synchronized的两条规定:

》线程解锁前,必须把共享变量的最新值刷新到主内存;

》线程加锁时,将清空工作内存中共享变量的值,从而使用共享变量是需要从主内存中重新读取最新的值(注意,加锁与解锁是同一把锁)

  原子性演示时,修饰的对象不同时,是互相不影响的。

2)可见性——volatile:

通过加入内存屏障和禁止重排序优化来实现,这种机制实现在CPU的指令层面,。

》对volatile变量写操作时,会在写操作后加入一条store屏障指令,将本地内存中的共享变量值刷新到主内存;

》对volatile变量读操作时,会在读操作前加入一条load屏障指令,从主内存中读取共享变量;

java程序入口方法可见性为public java synchronized 可见性_可见性

java程序入口方法可见性为public java synchronized 可见性_可见性_02

4、实例测试:

如果使用volatile修饰之前的计数器的值,是否可以获取正确的结果呢?

java程序入口方法可见性为public java synchronized 可见性_可见性_03

java程序入口方法可见性为public java synchronized 可见性_可见性_04

 

运行结果:

java程序入口方法可见性为public java synchronized 可见性_加锁_05

如上多次运行可发现,即使上方用volatile修饰,但是仍然无法保证结果,为什么呢?

java程序入口方法可见性为public java synchronized 可见性_加锁_06

因为add 方法中,实际执行了三步,在多个线程中执行时,出现问题,也证明volatile 这个关键字不具备原子性,

那volatile不适合如上计数场景,那volatile适合什么样的场景呢?

使用volatile必须具备两个特点:

1、对变量的写操作不依赖于当前值;

2、该变量没有包含在具有其他变量的不变的式子中。

常见使用方案:将volatile修饰的变量作为一个标志性变量,和双重检查机制的方案中。

java程序入口方法可见性为public java synchronized 可见性_可见性_07