这是我参与11月更文挑战的第11天,活动详情查看:2021最后一次更文挑战
i++问题
经过之前的学习,我们知道了i++这个操作分为了三个步骤:
- CPU从内存读取变量i的值
- CPU执行i+1操作
- CPU将第二部操作的结果赋值给变量i
上面三个步骤通过volatile关键字,可以保证1、3的原子性以及禁止使用高速缓存。但三个操作合并在一起就无法保证操作的原子性了。
CAS解决i++原子性
对于上面的i++问题,jdk提供了Atomic原子类解决i++原子操作,阅读各种博客的我也了解到这是由CAS实现的,并且达到了无锁编程,但是CAS真的是无锁吗?
假设定义以下变量,CAS的执行过程有以下几个步骤
private volatile long val;
- 通过val内存地址读取val的值
- 比较内存地址的值与1中读取的值是否相等
- 相等,将val内存地址指向的变量跟新为修改值
- 不等返回
下面我们来思考上面操作是否存在并发安全问题,判断一套操作是否存在并发安全问题,别无他法,只能在每一个写操作的地方想象上下文切换的动作,对比上下文切换是否对最终结果有影响。按照这个方法,你会发现,如果两个线程A,B同时执行到2,然后线程A进行上下文切换,线程B继续执行3,4操作。随后喜线程A恢复执行3,4步骤从而导致线程B的写入对A不可见。
这个问题的解决办法有俩:
- 在步骤1之前加锁,只需要把这个内存地址锁住,不让线程读取即可
- 将2,3两个操作变为一个原子性操作
思考完后,来瞧瞧jdk如何实现的。先找到AtomicInteger#getAndIncrement()方法:
我已经下载了最新版openjdk源码,用vsocde打开,ctrl+shift+f 全局搜索compareAndSwapInt。
。