哪位大神解释下[volatile不能保证原子性,也就不能保证线程安全]这句话
哪位大神解释下[volatile不能保证原子性,也就不能保证线程安全]这句话
哪位大神解释下[volatile不能保证原子性,也就不能保证线程安全]这句话
简单来说,volatile在多cpu环境下不能保证其它cpu的缓存同步刷新,因此无法保证原子性。
还是以最常用的i++来说吧,包含3个步骤
1,从内存读取i当前的值
2,加1
3,把修改后的值刷新到内存
对于普通变量来说多线程下1,2之间被中断,其它线程修改了i的值,那原来已经在1,2之间被中断的线程的i的值就已经无效了,所以多线程是不安全的。
另外对于普通变量来说,步骤1并不是每次都会从内存中读取,步骤3也并不会每次都保证会立即刷新到内存,详情见线程缓存的相关文章。
所以这里有两个问题,可见性和原子性,viloate只能保证可见性,即步骤1每次都重新读,步骤3每次都立即刷新到主内存。但1,2之间仍然会被中断,多个线程交叉修改,所以仍然不安全
原子操作是一些列的操作要么全做,要么全不做。锁机制可以保证原子性。而volatile 是一种弱的同步机制,只能确保共享变量的更新操作及时被其他线程看到,但不能保证原子性,比如线程1,2同时读到最新数据a,然后线程1试图递增变量a时,线程2已经率先修改并提交了,那么线程1操作的数据就是失效数据,导致读-改-写三个本该一起执行的操作失去了原子的含义。
保证线程安全必须保证顺序性,可见性和原子性。
顺序性,顾名思义,就是必须保证程序是按照你所预想的逻辑执行的。
可见性,写入缓存与从缓存读出是一个完整的动作,保证变化的值即时可见。这是volatile能保证的。
原子性,保证一个处理(或一段代码)不被打断地执行完毕,这是原子性。
原子性和可见性确实容易搞混,可见性比原子性控制范围更小,仅仅控制缓存的一次读写。而原子性控制整段处理。
举个例子:使用volatile声明一个变量 a,然后对变量a做如下操作。
a=a+1;
a=a+b;
volatile无法保证这两条语句不被打断的执行完毕,只有使用同步化关键字保证它的原子性才可以。
以上有个人理解,可能有不完善的地方。大体就是这个意思。
个人理解:原子性是指 多线程情况下 由于每个线程的CPU时间片用完或其他情况下,线程上线文切换,导致一系列操作没有执行完毕时,切换了线程。不可分割的操作被迫分开了,导致数据不一致问题。。保证一套流程走下来时数据必须前后一致
而volatile解决的是可见性问题 不是原子性问题。volatile只能保证每次读取到的结果是从主内存中获取,是最新的。
volatile 只能解决读取的值是最新的值,但是并不能解决线程上下文切换导致的指令切换问题
对于一个被声明为volatile的变量,每次去读这个变量的值时,jvm会先把这个值更新到最新值,再让你读,因此你读到的就是最新值,当时读到之后其它线程
有可能又改了这个变量的值,因此不是原子性,也不是线程安全的。