首页 > 其他 > 详细

volaile

时间:2021-03-07 08:55:36      阅读:27      评论:0      收藏:0      [点我收藏+]

1. volatile作用

volatile用以声明变量的值可能随时会别的线程修改,使用volatile修饰的变量会强制将修改的值立即写入主存,主存中值的更新会使缓存中的值失效(非volatile变量不具备这样的特性,非volatile变量的值会被缓存,线程A更新了这个值,线程B读取这个变量的值时可能读到的并不是是线程A更新后的值)。volatile会禁止指令重排。

2. volatile特性

 1)可见性。当多个线程访问同一个变量x时,线程1修改了变量x的值,线程1、线程2...线程n能够立即读取到线程1修改后的值。每个线程都有自己的缓存空间,对变量的操作时在缓存中进行的,之后再将修改的写到缓存中。当变量经过volatile修饰后,对此变量进行写操作时,会将当前处理器的被修改的变量强制更新到主存中,同时将其它处理器中的该变量值置为无效,需要重新到主存中读取。

 2)有序性。即程序执行时按照代码书写的先后顺序执行。在Java内存模型中,允许编译器和处理器对指令进行重排序,但是重排序过程不会影响到单线程程序的执行,却会影响到多线程并发执行的正确性。

 3)不具有原子性。在java中,只有对基本数据类型的读取和赋值是原子操作。而对于i++等运算操作都不是原子操作,因为他们都进行了多次原子操作。比如先读取j,再将j的值加给i,这就进行了两次操作。

例如:一个变量i被volatile修饰,有两个线程都要对i进行自加即i++,而i++的过程可以分为三步,首先读取i的值,然后对i的值加1,最后将得到的结果写到缓存和主存中。

线程A首先得到了i的值20,还没修改,发生阻塞,此时线程B开始,也读取到了i的值20,之后对其进行自加操作,得到21,将值写道缓存中,由于volatile的修饰,该值会刷到主存中。而由可见性可得,这个主存的值可以被其他线程可见。

此时问题就出现了,线程A已经读取到了i的值为20,也就是说读取的这个原子操作已经结束了,所以这个可见性已经晚了,当线程A阻塞结束后,继续对该变量自加得到101,再将值写到缓存并刷到内存。由此可见即使volatile具有可见性,也不能保证对它修饰的变量具有原子性。

3. volatile适用场景。

 1)适用于对变量的写操作不依赖于当前值,对变量的读取操作不依赖于非volatile变量。

 2)适用于读多写少的场景。可用作状态标志。

 3)JDK中volatie应用:JDK中ConcurrentHashMap的Entry的value和next被声明为volatile,AtomicLong中的value被声明为volatile。AtomicLong通过CAS原理(也可以理解为乐观锁)保证了原子性。

4.  volatile VS synchronized

 sychronized具有原子性、可见性以及有序性。volatile不会让线程阻塞,响应速度比synchronized高。

 

volaile

原文:https://www.cnblogs.com/yinghang/p/volatile.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!