CAS 其實是我們面試中的常客梁呈,因為它是原子類的底層原理,同時也是樂觀鎖的原理蘸秘,它的英文全稱是 Compare-And-Swap,中文叫做 “比較并交換”蝗茁,它是一種思想醋虏、一種算法。
在多線程的情況下哮翘,各個代碼的執(zhí)行順序是不能確定的颈嚼,所以為了保證并發(fā)安全,我們可以使用互斥鎖饭寺。
而 CAS 的特點是避免使用互斥鎖阻课,當多個線程同時使用 CAS 更新同一個變量時,只有其中一個線程能夠操作成功艰匙,而其他線程都會更新失敗限煞。
不過和同步互斥鎖不同的是,更新失敗的線程并不會被阻塞员凝,而是被告知這次由于競爭而導致的操作失敗署驻,但還可以再次嘗試。
CAS 被廣泛應用在并發(fā)編程領域中,以實現(xiàn)那些不會被打斷的數(shù)據(jù)交換操作旺上,從而就實現(xiàn)了無鎖的線程安全瓶蚂。該技術既能保證安全性,又不需要使用互斥鎖宣吱,能大大提升工具類的性能窃这。
ConcurrentHashMap 對于 CAS 的應用是比較廣泛的。
CAS 有什么缺點征候?
首先杭攻,CAS 最大的缺點就是 ABA 問題。
某個值假設從 A 變成了 B倍奢,再由 B 變回了 A朴上,此時,我們不僅認為它發(fā)生了變化卒煞,并且會認為它變化了兩次痪宰。
在這種場景下,我們使用 CAS畔裕,就看不到這兩次的變化衣撬,因為僅判斷 “當前的值和預期的值是否一致” 就是不夠的了。
所以 CAS 會認為變量的值在此期間沒有發(fā)生過變化扮饶。所以具练,CAS 并不能檢測出在此期間值是不是被修改過,它只能檢查出現(xiàn)在的值和最初的值是不是一樣甜无。
那么如何解決這個問題呢扛点?添加一個版本號就可以解決。
我們在變量值自身之外岂丘,再添加一個版本號陵究,那么這個值的變化路徑就從 A→B→A 變成了 1A→2B→3A,這樣一來奥帘,就可以通過對比版本號來判斷值是否變化過铜邮,這比我們直接去對比兩個值是否一致要更靠譜,所以通過這樣的思路就可以解決 ABA 的問題了寨蹋。
CAS 的第二個缺點就是自旋時間過長松蒜。
由于單次 CAS 不一定能執(zhí)行成功,所以 CAS 往往是配合著循環(huán)來實現(xiàn)的已旧,有的時候甚至是死循環(huán)秸苗,不停地進行重試,直到線程競爭不激烈的時候评姨,才能修改成功难述∮┣纾可是如果我們的應用場景本身就是高并發(fā)的場景,就有可能導致 CAS 一直都操作不成功胁后,這樣的話店读,循環(huán)時間就會越來越長。而且在此期間攀芯,CPU 資源也是一直在被消耗的屯断,這會對性能產(chǎn)生很大的影響。所以這就要求我們侣诺,要根據(jù)實際情況來選擇是否使用 CAS殖演,在高并發(fā)的場景下,通常 CAS 的效率是不高的年鸳。