前言
之前看过一些关于线程并发处理的文章,但是理解只停留于理论,最近在使用Netty框架的项目中再次遇到这类问题,并且发现对于volatile的使用依然存在疑惑,于是决定认真理解一些关于volatile的作用 。
提示:以下是本篇文章正文内容,下面案例可供参考
一、synchronized
java在解决线程并发问题,主要使用的是synchronized和volatile机制,不同之处在于处理多线程访问的时候,通过使用synchronized使得同一时刻只有单一线程;而volatile则是在多线程中用于保证变量修改之后取值的正确性,意思是这个值不然是未变化之前的,要不然就是确定修改结束后的,有些类似数据库的原子性。
二、volatile
1.理解原理
要想彻底理解volatile,需要先了解下JVM的内存模式;
JVM中包含一个JVM虚拟机栈,和一个线程栈;
线程栈即为每一个线程私有的栈,当一个线程需要给栈中对象引用值,栈中指针会去到内存堆中找到这个值;(如图)
接下来线程栈会自己保存这个变量,在接下来的步骤中,每当用到这个值,指针不再回去堆中找这个变量,而是直接对自己栈中的值进行引用;
直到修改结束,再把这对象值write回堆中;
所以问题就来了:因为如果是多线程,其他线程将从主内存中取来值,之后的操作都不会再从主内存中取值而是针对自己栈中的那个变量值;但是如果在这段时间里面主线程中的对象值发生了改变,那么由于其他线程不会去主线程中的对象取值,从而这个值的变化影响到后续的判断,这个有点类似于数据库中数据幻读的原因。
所以处理就是给主内存的变量值加一个volatile,这样就会强迫其他线程每次都来主内存中取这个值;
2.项目应用
线程pool中的主线程里面有一个记录server status 的变量:
private volatile ServerStatusEnum serverStatus = ServerStatusEnum.INIT;
public void setServerStatus(ServerStatusEnum serverStatus)
{
this.serverStatus = serverStatus;
}
然而在Work Processor中同时使用到了这个server status,所以如果不使用volatile,work线程将只会在对server status完成修改后才会返回到主内存,然后再次取值。
private void tickServerStatus()
{
if (serverStatus == ServerStatusEnum.STOP)
{
Boot.mutex.countDown();
return;
}
中途方法调用时,都不会取到Main Processor上 server status 可能变化的值。