大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。
Jetbrains全系列IDE稳定放心使用
1. 背景
我们知道,synchronized就是一种独占锁,独占锁是一个悲观锁,会导致其他所有需要锁的线程挂起,等待持有锁的线程释放锁。而另一种更加有效的锁就是乐观锁,CAS就是一种乐观锁
2. CAS原理
CAS(Compare And Swap),比较并交换。我们知道,如果我要对一个变量进行操作,可以分为三个步骤
- 读取该变量的值
- 进行一系列的运算得到新的结果
- 将运算的结果保存
这儿需要知道CAS中有三个概念:内存地址的值V,旧值(从内存地址读取到的值)A,新值(进行操作后的结果值)B。对应上面三个步骤就是:值V保存在内存中,要修改的时候,会先去读取该内存中的值,读取到的值为A,此时A=V,然后进行操作得到结果B,此时需要将B写入内存才算是对该变量进行了完整的修改。那么此时需要再去读取内存中的值,判断该值是否等于A,如果等于,那么就直接将B写入。如果不等于,说明你在运算的过程中,其他的线程对该变量已经做了修改,那么你此时得到的这个B是没有意义的。不能写入。只能再次重复上面的操作(自旋),重新读取内存中的值,计算之后再进行比较,直到B可以被保存为止。这就是CAS的原理。
3. ABA问题
但是这种方式会有一个问题:ABA,就是说你在要保存B的时候,会去读取内存中的值判断是否和A相等,确保这期间没有其他线程操作过该变量。但是如果相等的话,你能确认这期间这个值没有被修改过吗?有可能期间被多次修改了,只不过最后得到的值恰好和原来的A相等。所以你不能保证相等时就是没有被修改过。这种情况可以加一个版本号来判断。例如1A-2B-3A,这样你就知道这个A其实已经不是原来的那个A了。
4. 缺点
因为该机制是没有加锁的,所有线程都可以任意操作该变量,虽然可以确保线程安全,但是如果并发太大,导致很多线程都在操作该变量,这会导致有大量的线程进行自旋,这无疑是增加了CPU的资源消耗。
5. 疑问
其实我自己有个疑问,这个真的安全吗?在保存B之前会判断内存中的值是否和A相等,相等就可以保存B。那如果有多个线程在操作该变量,操作完之后去读取内存中的值,并和各自线程中的A进行比较,假设这些线程都是在其他线程写入之前读取到内存中的值,也就是这几个线程读取到的值都和A相等,那么在写入的时候不就会出现先写入B值的线程的值会被后面写入的覆盖掉吗?
这个可能是自己对操作系统底层的原理不太了解,所以会有这样的疑问吧。
希望会这个问题的大佬不吝赐教,也希望自己以后在搞懂这个问题之后,来这儿将这个问题解决掉。
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/184106.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...