volatile的内存可见性认识

要谈此字的作用,必先谈谈JAVA的内存模型。百度谷歌后大致可以得出三点:

1.所有的变量都存储在主内存中。

2.每条线程中还有自己的工作内存,线程的工作内存中保存了被该线程所使用到的变量(这些变量是从主内存中拷贝而来)。线程对变量的所有操作(读取,赋值)都必须在工作内存中进行。

3.不同线程之间也无法直接访问对方工作内存中的变量,线程间变量值的传递均需要通过主内存来完成。

图示如下:

结合上述一看,此模型在多线程环境下必然会出现数据“脏读”等问题。例如:i=1++;

执行线程必须先在自己的工作线程中对变量i所在的缓存行进行赋值操作,然后再写入主存当中。而不是直接将数值1写入主存当中。

比如同时有2个线程执行这段代码,假如初始时i的值为1,那么我们希望两个线程执行完之后i的值变为3。但是事实会是这样吗?

可能存在下面一种情况:初始时,两个线程分别读取i的值存入各自所在的工作内存当中,然后线程1进行加1操作,然后把i的最新值2写入到内存。此时线程2的工作内存当中i的值还是1,进行加1操作之后,i的值为2,然后线程2把i的值写入内存。

最终结果i的值是2,而不是3。这就是著名的缓存一致性问题。通常称这种被多个线程访问的变量为共享变量。

那么如何确保共享变量在多线程访问时能够正确输出结果呢?足智多谋且经验丰富的各位仁兄肯定想的到,这不就是多线程安全的问题吗?多简单的事啊,加个锁或者synchronized不就得了?!锁和synchronized关键字是防止多个线程同时执行一段代码,那么就会很影响程序执行效率,而volatile关键字在某些情况下性能要优于锁和synchronized,但是特别注意的是:volatile关键字是无法替代锁和synchronized关键字的,因为volatile关键字无法保证操作的原子性!!!volatile关键字无法保证操作的原子性!!!volatile关键字无法保证操作的原子性!!!重要的事情说三遍!!!

举个简单简单例子,大家常用的退出循环:

private boolean stop = false;

......

while(!stop){

    doSomething;//thread1

}

......

this.stop = true;//thread2

          在多线程环境下,可能存在下面一种情况:同时有2个线程执行这段代码,每个线程在运行过程中都有自己的工作内存,那么线程1在运行的时候,会将stop变量的值拷贝一份放在自己的工作内存当中。当线程2更改了stop变量的值之后,但是还没来得及写入主存当中,线程2转去做其他事情了,那么线程1由于不知道线程2对stop变量的更改,因此还会一直循环下去。但是加上volatile就不一样了,会强制将修改的值立即写入主存,当线程2进行修改时,会导致线程1的工作内存中缓存变量stop的缓存行无效所以线程1再次读取变量stop的值时会去主存读取。

          在线程2修改stop值时(当然这里包括2个操作,修改线程2工作内存中的值,然后将修改后的值写入内存),会使得线程1的工作内存中缓存变量stop的缓存行无效,然后线程1读取时,发现自己的缓存行无效,它会等待缓存行对应的主存地址被更新之后,然后去对应的主存读取最新的值。

         那么线程1读取到的就是最新的正确的值,如此即可体现volatile的内存可见性的zuo作用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值