Java AtomicBoolean (Java程式碼實戰-008)

FrankYou發表於2018-06-20

值得一提的是,Java的AtomXXX類並不是使用了鎖的方式進行同步,而是採用了一種新的理念,叫做CAS(Compare And Swap)
CAS是一組CPU原語指令,用來實現多執行緒下的變數同步(原子操作)。在 X86下的指令CMPXCHG實現了CAS,前置LOCK既可以達到原子性操作。 
由於CAS原語的直接操作與計算機底層的聯絡很大,CAS原語有三個引數,記憶體地址,期望值,新值。我們在Java中一般不去直接寫CAS相關的程式碼,JDK為我們封裝在AtomXXX中,因此,我們直接使用就可以了。 

CAS有3個運算元,記憶體值V,舊的預期值A,要修改的新值B。當且僅當預期值A和記憶體值V相同時,將記憶體值V修改為B,否則什麼都不做。

CAS操作不需要不需要阻塞執行緒(加鎖、解鎖)以及切換執行緒狀態,效率更高。

使用AtomBoolean來實現原子操作

package atomactions;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * Created by xfyou 2018/6/20 16:29.
 */
public class BarWorker implements Runnable {

    /**
     * <p>
     * AtomicBoolean是java.util.concurrent.atomic包下的原子變數,這個包裡面提供了一組原子類。
     * <p>
     * 其基本的特性就是在多執行緒環境下,當有多個執行緒同時執行這些類的例項包含的方法時,具有排他性,即當某個執行緒進入方法,執行其中的指令時,不會被其他執行緒打斷,而別的執行緒就像自旋鎖一樣,一直等到該方法執行完成,才由JVM從等待佇列中選擇一個另一個執行緒進入,這只是一種邏輯上的理解。
     * <p>
     * 實際上是藉助硬體的相關指令來實現的,不會阻塞執行緒(或者說只是在硬體級別上阻塞了)。
     * <p>
     * 例如AtomicBoolean,在這個Boolean值的變化的時候不允許在之間插入,保持操作的原子性。方法和舉例:compareAndSet(boolean expect, boolean update)。
     * 這個方法主要兩個作用
     * 1. 比較AtomicBoolean和expect的值,如果一致,執行方法內的語句。其實就是一個if語句
     * 2. 把AtomicBoolean的值設成update比較最要的是這兩件事是一氣呵成的,這連個動作之間不會被打斷,任何內部或者外部的語句都不可能在兩個動作之間執行。為多執行緒的控制提供瞭解決的方案。
     */
    private static AtomicBoolean exist = new AtomicBoolean(false);

    @Override
    public void run() {
        String name = Thread.currentThread().getName();
        if (exist.compareAndSet(false, true)) {
            System.out.println(name + " enter");
            try {
                System.out.println(name + " working");
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                // do nothing
            }
            System.out.println(name + " leave");
            exist.set(false);
        } else {
            System.out.println(name + " give up");
        }
    }

    /**
     * 僅僅一個執行緒進行工作,因為exists.compareAndSet(false, true)提供了原子性操作,比較和賦值操作組成了一個原子操作
     *
     * @param args args
     */
    public static void main(String[] args) {
        BarWorker bw = new BarWorker();
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        for (int i = 0; i < 5; i++)
            executorService.execute(bw);
        executorService.shutdown();
    }
}

 一種可能的輸出結果為:

pool-1-thread-1 enter
pool-1-thread-1 working
pool-1-thread-3 give up
pool-1-thread-4 give up
pool-1-thread-5 give up
pool-1-thread-2 give up
pool-1-thread-1 leave

java併發包是在建立在volatile和CAS基礎上的

 

相關文章