CAS(Compare and swap)比較和替換是設計併發算法時用到的一種技術。簡單來講,比較和替換是使用一個指望值和一個變量的當前值進行比較,若是當前變量的值與咱們指望的值相等,就使用一個新值替換當前變量的值。這聽起來可能有一點複雜可是實際上你理解以後發現很簡單,接下來,讓咱們跟深刻的瞭解一下這項技術。java
在程序和算法中一個常常出現的模式就是「check and act」模式。先檢查後操做模式發生在代碼中首先檢查一個變量的值,而後再基於這個值作一些操做。下面是一個簡單的示例:算法
class MyLock { private boolean locked = false; public boolean lock() { if(!locked) { locked = true; return true; } return false; } }
上面這段代碼,若是用在多線程的程序會出現不少錯誤,不過如今請忘掉它。多線程
如你所見,lock()方法首先檢查locked>成員變量是否等於false,若是等於,就將locked設爲true。併發
若是同個線程訪問同一個MyLock實例,上面的lock()將不能保證正常工做。若是一個線程檢查locked的值,而後將其設置爲false,與此同時,一個線程B也在檢查locked的值,又或者,在線程A將locked的值設爲false以前。所以,線程A和線程B可能都看到locked的值爲false,而後二者都基於這個信息作一些操做。這就是ABA的問題。ide
舉個例子,你拿着一個裝滿錢的手提箱在飛機場,此時過來了一個火辣性感的美女,而後她很暖昧地挑逗着你,並趁你不注意的時候,把用一個如出一轍的手提箱和你那裝滿錢的箱子調了個包,而後就離開了,你看到你的手提箱還在那,因而就提着手提箱去趕飛機去了。atom
爲了在一個多線程程序中良好的工做,」check then act」 操做必須是原子的。原子就是說」check「操做和」act「被當作一個原子代碼塊執行。不存在多個線程同時執行原子塊。spa
下面是一個代碼示例,把以前的lock()方法用synchronized關鍵字重構成一個原子塊。線程
class MyLock { private boolean locked = false; public synchronized boolean lock() { if(!locked) { locked = true; return true; } return false; } }
如今lock()方法是同步的,因此,在某一時刻只能有一個線程在同一個MyLock實例上執行它。設計
原子的lock方法其實是一個」compare and swap「的例子。同步
如今CPU內部已經執行原子的CAS操做。Java5以來,你可使用java.util.concurrent.atomic包中的一些原子類來使用CPU中的這些功能。
下面是一個使用AtomicBoolean類實現lock()方法的例子:
public static class MyLock { private AtomicBoolean locked = new AtomicBoolean(false); public boolean lock() { return locked.compareAndSet(false, true); } }
locked變量再也不是boolean類型而是AtomicBoolean。這個類中有一個compareAndSet()方法,它使用一個指望值和AtomicBoolean實例的值比較,和二者相等,則使用一個新值替換原來的值。在這個例子中,它比較locked的值和false,若是locked的值爲false,則把修改成true。
若是值被替換了,compareAndSet()返回true,不然,返回false。
使用Java5+提供的CAS特性而不是使用本身實現的的好處是Java5+中內置的CAS特性可讓你利用底層的你的程序所運行機器的CPU的CAS特性。這會使還有CAS的代碼運行更快。