volatile : 可见性、有序性。记住了,人家不保证原子性的。
先说说volatile关键字
被volatile关键字修饰的变量,再多线程中,一个线程修改他会立即被其他线程看到,可能这样你不太理解,首先我们看那一下java内存模型图吧。
也就是说,我们看到了,当一个线程想要访问一个变量的时候,我们首先要去主内存读取变量,然后拿到自己的工作内存,然后做相应的处理,最后由jvm刷新到主内存中去。(当然什么时候刷新到主内存中去,这就不能确定了。不过在我们看来这个时间是非常短的,但是线程之间就不是了,可能就会发生脏读。)
volatile关键字,当据,jvm知道这个变量是使用volatile修饰,那么他就会立即刷新到主内存中去,保证其他线程能够立即看到这个变量的修改,读取最新值。这也是volitile关键字的可见性。
下面再说一下有序性吧(重点哦) 大厂一般都问。
jvm在为了运行效率提高,可能会对输入的指令进行排序,他不会保证指令执行的顺序是我们写入代码的顺序,但是他会保证运行的结果是一致的。(单线程情况下)
volatile有先天性的禁止重排序特性。同时: lock、Synchronized 都可以保证有序性
happens-before(先行发生原则) 差不多说一下前四条吧
1、写在上面的代码执行要在写在下面的代码前面
2、一个unLock操作先行发生于后面对同一个锁的lock操作 比如这样 lock unlock lock unlock 其中第一个unlock要早于 第二个lock操作执行。
3、对一个变量的写操作先行发生于后面对这个变量的读操作
4、如果操作A先行发生于操作B,而操作B又先行发生于操作C,则可以得出操作A先行发生于操作C
5、Thread对象的start()方法先行发生于此线程的每个一个动作
6、对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生
7、线程中所有的操作都先行发生于线程的终止检测,我们可以通过Thread.join()方法结束、Thread.isAlive()的返回值手段检测到线程已经终止执行
8、一个对象的初始化完成先行发生于他的finalize()方法的开始
**************************重点**************************************
人家问你为什么volatile可以保证可见性,你要这样回答,
第一:使用volatile关键字会强制将修改的值立即写入主存;
第二:使用volatile关键字的话,当线程2进行修改时,会导致线程1的工作内存中缓存变量stop的缓存行无效(反映到硬件层的话,就是CPU的L1或者L2缓存中对应的缓存行无效);
第三:由于线程1的工作内存中缓存变量stop的缓存行无效,所以线程1再次读取变量stop的值时会去主存读取。
那么在线程2修改stop值时(当然这里包括2个操作,修改线程2工作内存中的值,然后将修改后的值写入内存),会使得线程1的工作内存中缓存变量stop的缓存行无效,然后线程1读取时,发现自己的缓存行无效,它会等待缓存行对应的主存地址被更新之后,然后去对应的主存读取最新的值。
那么线程1读取到的就是最新的正确的值。