FAA
func transferFaa(balance *int32, amount int, done chan bool) { atomic.AddInt32(balance, int32(amount)) done <- true }
java.util.concurrent.atomic.AtomicLong#getAndAdd
- FAA原语
获取变量当前值,然后把它做个加法,且保证该操作的原子性,一行代码即可。你开始好奇了,那CAS还有何意义?
该案例肯定FAA更合适,但CAS适用范围更广。
类似逻辑:先读数据,做计算,然后更新数据,无论这个计算啥样,都可用CAS保护数据安全。
但FAA逻辑局限于简单加减法。所以并非说CAS没有意义。
使用CAS反复重试赋值比较耗费CPU,因为for循环如果赋值不成,会立即进入下一次循环,没有等待的。如果线程间碰撞频繁,经常反复重试,这重试的线程会占用大量CPU时间,系统性能就会下降。
缓解这问题的一个方法是使用Yield(), 大部分编程语言都支持Yield()系统调用。
Yield()作用
告诉os,让出当前线程占用的CPU给其他线程。每次循环结束前调用下Yield(),可在一定程度上降低CPU使用率,缓解该问题。也可在每次循环结束后,Sleep()小段时间,但这样性能会严重下降。
所以,这种方法它只适于线程碰撞不太频繁,即执行CAS不需要重试这样的场景。
用锁、CAS和FAA完整实现账户服务
ttps://github.com/shenyachen/JKSJ/blob/master/study/src/main/java/com/jksj/study/casAndFaa/CASThread.java
https://github.com/xqq1994/algorithm/blob/master/src/main/java/com/test/concurrency/MutxLock.java
https://github.com/xqq1994/algorithm/blob/master/src/main/java/com/test/concurrency/CAS.java
参考
https://time.geekbang.org/column/article/130743