volatile与同步

区别是什么呢?

首先相同点:都保证可见性、有序性

区别:volatile不保证原子性

对于volatile关键字,当且仅当满足以下所有条件时可使用:

1. 对变量的写入操作不依赖变量的当前值,或者你能确保只有单个线程更新变量的值。//多个更新,同步问题
2. 该变量没有包含在具有其他变量的不变式中。//不能保证原子性

关于这个两个规则可能有点疑问:

第一条简单,就是说只有单个线程进行读操作

第二条指的其实是不改变变量值的语句,比如a>b

volatile关键字解决的是内存可见性的问题,会使得所有对volatile变量的读写都会直接刷到主存,即保证了变量的可见性。这样就能满足一些对变量(原始变量)可见性有要求而对读取顺序没有要求的需求。

使用volatile关键字仅能实现对原始变量(如boolen、 short 、int 、long等)操作的原子性,但需要特别注意, volatile不能保证复合操作的原子性,即使只是i++,实际上也是由多个原子操作组成:read i; inc; write i,假如多个线程同时执行i++,volatile只能保证他们操作的i是同一块内存,但依然可能出现写入脏数据的情况。

************************************************************************************************************************************************

关于这里一直很迷惑,既然变量值改变以后就立刻刷新到主内存,而且其他使用这个变量的地方都会重新到主内存去读,为何还会引入脏数据?

看了很多解释都是一样的说法,就是比如a线程已经读取变量值10,然后阻塞,b线程再修改变量值10->11,然后a再修改变量值,造成修改的还是10。

        72: getstatic     #18                 // Field r:I
        75: iconst_1
        76: iadd
        77: putstatic     #18                 // Field r:I
 

一个简单的volatile变量的自增操作的字节码是这样的

就是说a线程已经读取到变量值,这个原子操作已经结束,下一个操作是iadd,不需要再读取数据,所以这个值是老的,没有更新的值 

volatile用法举例:

避免指令重排,比如一个boolean的值控制后续逻辑,单线程则没有问题,如果是多线程,可能出现指令重排,导致代码未执行,而boolean已经发生变化,导致出现bug 

借用java内存模型图片一张:

https://blog.csdn.net/y874961524/article/details/61617778

猜你喜欢

转载自blog.csdn.net/jianpan_zouni/article/details/84324786