並發中CAS的含義及Java中AtomicXXX類的分析

來源:互聯網
上載者:User

維基百科:

In computer science, the compare-and-swap CPU instruction ("CAS") (or the Compare & Exchange - CMPXCHG instruction in the x86 and Itanium architectures) is a special instruction that atomically (regarding intel x86, lock prefix should be there to make it really atomic) compares the contents of a memory location to a given value and, only if they are the same, modifies the contents of that memory location to a given new value. This guarantees that the new value is calculated based on up-to-date information; if the value had been updated by another thread in the meantime, the write would fail. The result of the operation must indicate whether it performed the substitution; this can be done either with a simple Boolean response (this variant is often called compare-and-set), or by returning the value read from the memory location (not the value written to it). Compare-and-Swap (and Compare-and-Swap-Double) has been an integral part of the IBM 370(and all successor) architectures since 1970. The operating systems which run on these architectures make extensive use of Compare-and-Swap (and Compare-and-Swap-Double) to facilitate process (i.e., system and user tasks) and processor (i.e., central processors) parallelism while eliminating, to the greatest degree possible, the "disabled spin locks" which were employed in earlier IBM operating systems. In these operating systems, new units of work may be instantiated "globally", into the Global Service Priority List, or "locally", into the Local Service Priority List, by the execution of a single Compare-and-Swap instruction. This dramatically improved the responsiveness of these operating systems.

===================================================

總結:CAS是硬體CPU提供的元語,它的原理:我認為位置 V 應該包含值 A;如果包含該值,則將 B 放到這個位置;否則,不要更改該位置,只告訴我這個位置現在的值即可。

Java並發庫中的AtomicXXX類均是基於這個元語的實現,以AtomicInteger為例:

    public final int incrementAndGet() {
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return next;
}
}

public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}

其中,unsafe.compareAndSwapInt()是一個native方法,正是調用CAS元語完成該操作。

===================================================

順便說下volatile。

根據Java Language Specification中的說明, jvm系統中存在一個主記憶體(Main Memory或Java Heap Memory),Java中所有變數都儲存在主存中,對於所有線程都是共用的。

每條線程都有自己的工作記憶體(Working Memory),工作記憶體中儲存的是主存中某些變數的拷貝,線程對所有變數的操作都是在工作記憶體中進行,線程之間無法相互直接存取,變數傳遞均需要通過主存完成。

所以,同一變數的值在工作記憶體和主存中可能不一致。volatile其實是告訴處理器, 不要將我放入工作記憶體, 請直接在主存操作我。

===================================================

回到AtomicInteger,注意到value的聲明:

private volatile int value;

通過前面對volatile的介紹可以知道,直接對volatile的賦值和讀取操作是無須加鎖的,見源碼:

  public final int get() {
return value;
}

public final void set(int newValue) {
value = newValue;
}

注意:volatile的這種作用對double和long無效,因為JVM中將對double或long的賦值或讀取操作拆成2個32位元的操作。

===================================================

那麼,為什麼自增操作要通過CAS來完成呢?仔細觀察incrementAndGet()方法,發現自增操作其實拆成了兩步完成的:

int current = get(); 
int next = current + 1;

由於valatile只能保證讀取或寫入的是最新值,那麼可能出現以下情況:

1 A線程執行get()操作,擷取current值(假設為1)

2 B線程執行get()操作,擷取current值(為1)

3 B線程執行next = current + 1操作,next = 2

4 A線程執行next = current + 1操作,next = 2

這樣的結果明顯不是我們想要的,所以,自增操作必須採用CAS來完成。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.