一个问题
思考一个问题,假设有一个变量i=0,两个并发的程序同时对i进行i++的操作,会发生什么事情,i最终的值会是2吗?
在理想的状态下,cpu先运行程序1,对i进行+1操作,然后再运行程序2,最终i变成了2
但是事实上,i++操作并非一个原子操作,它由三条原子操作组成
所以在现实情况下,有可能是下面的情况
左边的情况将会满足程序的预期,但是有可能出现右边的情况,i最终的值为1,就不满足我们程序的预期了
我们是否可以把i++作为一个原子操作呢,可以是可以,但是,如果i++作为了一个原子操作。我希望的是i+=2呢,是不是也要把i+=2作为一个原子操作。
CAS原子操作
人们想出了一个聪明的方法,系统提供一个原子操作CAS(compare and swap 或 Compare And Set)比较并交换,需要传递三个值,数据所在地址,数据过去的值,数据需要更新的值。
cpu会先比较传入数据原来的值是否和内存中当前的值是否相等,如果相等才更新内存中的值,否则操作失败。 对于刚才的i++ 可以使用cas(&i, i, i + 1)替代,那么如果操作失败了呢?那就循环重新再来一次,直到成功
while(! cas(&i,i, i+1));
ABA
CAS会出现的一个经典问题就是ABA了,比如说:
- 一个线程1获取到内存中a的值为A
- 然后线程2把a改为了B
- 然后线程2又把a改为了A
- 最后线程A再调用CAS,它以为a变量没有被改过。执行成功
解决方法:版本号
- 对不仅需要传递值,还需要传递版本号,只有值相等且版本号相等才认为该值没有被修改过