博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
解析java中volatile关键字
阅读量:4332 次
发布时间:2019-06-06

本文共 2501 字,大约阅读时间需要 8 分钟。

在Java多线程编程中经常volatile,有时候这个关键字和synchronized 或者lock经常有人混淆,具体解析如下: 

在多线程的环境中会存在成员变量可见性问题: java的每个线程都存在一个线程栈的内存空间,该内存空间保存了该线程运行时的变量信息,当线程访问某一个变量值的时候首先会根据这个变量的地址找到对象的堆内存或者是栈堆存(原生数据类型)中的具体的内容,然后把这个内同赋值一个副本保存在本线程的线程栈中,紧接着对这个变量的一切操作在线程完成退出之前都和堆栈内存中的变量内容是没有关系的,操作的是自己线程栈中的副本。当操作完后会把操作完的结果写回到主内存中。假如有两个线程A和B,同事操作某一个变量x;A对x进行了加1操作,那么B获取的副本可能是x加1后的结果,也可能是x;为了保证获取内存中最新的数据变量 需要加上 volatile 关键字,这样在每次对x进行操作的时候都会去检查下线程栈中的变量的值是不是和住内存中变量的值一样。如果不一样会重新load

public class ThreadSee {//t1线程会根据flag的值做对应的操作,主线程会更改t1的值 public static void main(String[] args) throws InterruptedException {        ThReadTest th=  new ThReadTest();        Thread t1 = new Thread(th);        t1.start();        Thread.sleep(1000);        th.changeFlag();        Thread.sleep(2000);        System.out.println(th.getFlag());    }}class ThReadTest implements Runnable{   //线程访问变量时会把其load到对应的线程栈中,每次操作时都要获取内存中最新的数据    private  volatile boolean  stopflag;    @Override    public void run() {        int i=0;        while(!stopflag){            i++;            System.out.println("=="+Thread.currentThread().getName());        }        System.out.println("Thread finish:"+i);    }    public void changeFlag(){        this.stopflag=true;        System.out.println(Thread.currentThread().getName()+"***********");    }    public boolean getFlag(){        return stopflag;    }}

上述代码如果去掉volatile,会一直死循环执行下去。 

但是volatile不能保证线程安全的同步 
eg:

public class ThreadSave implements Runnable{
static ThreadSave sync = new ThreadSave(); static volatile int j=0; //Lock lock =new ReentrantLock(); public void inscane(){ // lock.lock(); for(int i=0;i<10000000;i++){ j++; } // lock.unlock(); } @Override public void run() { inscane(); } public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(sync); Thread t2 = new Thread(sync); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println(j); }}

根据上述代码执行的结果不是预期20000000, 

因为对于volatile修饰的变量,jvm虚拟机只是保证从主内存加载到线程工作内存的值是最新的 
例如假如线程1,线程2 在进行线程栈与主内存read,load 操作中,发现主内存中count的值都是5,那么都会加载这个最新的值 
在线程1堆count进行修改之后,会write到主内存中,主内存中的count变量就会变为6 
线程2由于已经进行read,load操作,在进行运算之后,也会更新主内存count的变量值为6 
导致两个线程及时用volatile关键字修改之后,还是会存在并发的情况。 
综上所述: 
volatile只会保证线程去做一个检查当前线程栈的变量值和主内存中数据值是否一样的这么一个动作,只此而已。而lock或者是synchronized 会保证某一时刻只有单个线程进入该方法,从而确保其线程安全性。 
所以在如果多个线程去修改一个volatile变量那么没有实际的逻辑意义。如果一个线程去修改其他的线程依赖修改的变量值,此时是有作用的

 

转载于:https://www.cnblogs.com/zhengwenqiang/p/6804673.html

你可能感兴趣的文章
基本数据结构和算法系列---栈和队列
查看>>
sqlconnection dispose()与close()的区别
查看>>
git 一般用法
查看>>
Json
查看>>
poj1236Network of Schools Tarjan裸题
查看>>
项目管理过程
查看>>
泛型使用
查看>>
Employment Planning[HDU1158]
查看>>
hdu2089:不要62(基础数位dp)
查看>>
Tools
查看>>
JS获取第二个横杠后面的内容
查看>>
excel 导入MYSQL
查看>>
P3038 [USACO11DEC]牧草种植Grass Planting
查看>>
23 个最有吸引力和免费的Flash图像轮廓
查看>>
给label添加点击事件
查看>>
eterna 第一个案例
查看>>
新部署到服务器 报 The requested URL /home/profession was not found on this server. 错误
查看>>
hadoop从非HA转到NAMENODE HA时需要注意的一个问题
查看>>
KnockoutJs学习笔记(十一)
查看>>
访问修饰符public、private、protect、default范围
查看>>