與基於鎖的方案相比,非阻塞算法在設計和實現上都要負責得多,但它們在可伸縮性和活躍性上擁有巨大的優點。 原子變量提供了與volatile類型變量相同的內存語義,此外還支持原子的更新操做,從而使它們更加適用於實現計數器、序列發生器和統計數據收集等,同時還能比基於鎖的方法提供更高的可伸縮性。 獨佔鎖是一種悲觀技術----它假設最壞的狀況。 如今,幾乎全部的現代處理器中都包含了某種形式的原子讀-改-寫指令,例如比較並交換(Compare-and-Swap)或者關聯加載/條件存儲(Load-Linked/Store-Condition)。算法
CAS包含了3個操做數----須要讀寫的值V、進行比較的值A和擬寫入的新值B。當且僅當V的值等於A時,CAS纔會經過原子方式用新值B來更新V的值,不然不會執行任何操做,不管V的值是否等於A,都將返回V的原值。 當多個線程嘗試使用CAS同時更新同一個變量時,只有其中一個線程能更新變量的值,而其餘線程都將失敗,然而,失敗的線程並不會掛起,而是被告知在此次競爭中失敗,並能夠再次嘗試。數組
在Java5.0中引入了地城的支持,在int、long和對象的引用等類型上都公開了CAS操做,而且JVM把它們編譯爲底層提供的最有效方法。線程
共有12個原子變量類,可分爲4組:標量類(Scalar)、更新器類、數組類以及複合變量類。最經常使用的原子變量就是標量類:AtomicInteger、AtomicLong、AtomicBoolean以及AtomicReference。全部這些類都支持CAS,此外,AtomicInteger和AtominLong還支持算術運算。設計
若是在某種算法中,一個線程的失敗或掛起不會致使其餘線程也失敗或掛起,那麼這種算法就被稱爲非阻塞算法。若是在算法的每一個步驟中都存在某個線程可以執行下去,那麼這種算法也被稱爲無鎖(Lock-Free)算法。對象
ABA問題是一種異常現象:若是在算法中的節點能夠被循環使用,那麼在使用「比較並交換」指令時就可能出現這種問題。在CAS操做中將判斷「V的值是否仍然爲A?」,而且若是是的話就繼續執行更新操做,在大多數狀況下,包括本章給出的示例,這種判斷是徹底足夠的。然而,有時候還須要知道「自從上次看到V的值爲A以來,這個值是否發生了變化?」,在某些算法中,若是V的值首先由A變成B,再由B變成A,那麼仍然被認爲是發生了變化,並須要從新執行算法中的某些步驟。 解決ABA問題的一個簡單方法是:不是更新某個引用的值,而是更新兩個值,包括一個引用和一個版本號。即便這個值由A變爲B,而後又變爲A,版本號也將是不一樣的。 AtomicStampedReference、AtomicMarkableReference支持在兩個變量上執行原子的條件更新。AtomicStampedReference將更新一個「對象-引用」二元組,經過在引用上加上「版本號」,從而避免ABA問題。AtomicMarkableReference將更新一個「對象引用-布爾值」二元組,在某些算法中將經過這種二元組使節點保存在鏈表中同時又將其標記爲「已刪除的節點」。內存