1. 程式人生 > >Java原子類中CAS的底層實現

Java原子類中CAS的底層實現

sun 如果 inter trace r語 接下來 ont oop cep

Java原子類中CAS的底層實現

從Java到c++到匯編, 深入講解cas的底層原理.

介紹原理前, 先來一個Demo

以AtomicBoolean類為例.先來一個調用cas的demo.

主線程在for語句裏cas忙循環, 直到cas操作成功返回true為止.

而新開的一個縣城new Thread 會在4秒後,將flag設置為true, 為了讓主線程能夠設置成功.(因為cas的預期值是true, 而flag被初始化為了false)

現象就是主線程一直在跑for循環. 4秒後, 主線程將會設置成功, 然後輸出時間差, 然後終止for循環.

public class TestAtomicBoolean {
    public static void main(String[] args) {
        AtomicBoolean flag = new AtomicBoolean(false);

        long start = System.currentTimeMillis();

        new Thread(()->{
            try {
                Thread.sleep(4000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            flag.set(true);
        }).start();

        for(;;){
            if(flag.compareAndSet(true,false)){
                System.out.println(System.currentTimeMillis() - start);
                System.out.println("inner loop OK!");
                break;
            }
        }
    }
}

這裏只是舉了一個例子, 也許這個例子也不太恰當, 本文只是列出了這個api的調用方法而已, 重點在於介紹compareAndSet()方法的底層原理.

Java級源碼AtomicBoolean.java

發現AtomicBoolean的compareAndSet()調用的是unsafe裏的compareAndSwapInt()方法.

技術分享圖片

Java級源碼Unsafe.java

有的同學可能好奇, 其中的unsafe是怎麽來的.

在AtomicBoolean類中的靜態成員變量:

技術分享圖片

如果還要細究Unsafe.getUnsafe()是怎麽實現的話....那麽我再貼一份Unsafe類裏的getUnsafe的代碼:

首先, 在Unsafe類裏, 自己就有了一個自己的實例.(單例)

技術分享圖片

然後Unsafe類裏的getUnsafe()方法會進行檢查, 最終會return這個單例 theUnsafe.

技術分享圖片

剛剛跑去取介紹了getUnsafe()方法...接下來繼續講解cas...

剛才說到了AtomicBoolean類裏的compareAndSet()方法內部其實調用了Unsafe類裏的compareAndSwapInt()方法.

Unsafe類裏的compareAndSwapInt源碼如下:

(OpenJDK8的源碼裏路徑: openjdk/jdk/src/share/classes/sun/misc/Unsafe.java)

技術分享圖片

發現這裏是一段native方法.說明繼續看源碼的話, 從這裏就開始脫離Java語言了....

c++級源碼Unsafe.cpp

本源碼在OpenJDK8裏的路徑為: openjdk/hotspot/src/share/vm/prims/unsafe.cpp

技術分享圖片

(這裏臨時跑題一下: 如果說要細究 UNSAFE_ENTRY 是什麽的話...UNSAFE_ENTRY 就是 JVM_ENTRY, 而 JVM_ENTRY 在interfaceSupport.hpp裏面定義了, jni相關.如果想看的話, 源碼路徑在OpenJDK8中的路徑是這個:

openjdk/hotspot/src/share/vm/runtime/interfaceSupport.hpp)

回到本文的主題cas....上面截圖的這段代碼, 最後一句是return, 發現其中的使用到的是Atomic下的cmpxchg()方法.

c++級源碼atomic.cpp

本段源碼對應OpenJDK8的路徑是這個: openjdk/hotspot/src/share/vm/runtime/atomic.cpp

技術分享圖片

其中的cmpxchg為核心內容. 但是這句代碼根據操作系統和處理器的不同, 使用不同的底層代碼.

技術分享圖片

而atomic.inline.hpp裏聲明如下:

可見 ...不同不同操作系統, 不同的處理器, 都要走不同的cmpxchg()方法的實現.

技術分享圖片

咱們接下來以其中的linux操作系統 x86處理器為例 , atomic_linux_x86.inline.hpp

匯編級源碼atomic_linux_x86.inline.hpp

OpenJDK中路徑如下: openjdk/hotspot/src/os_cpu/linux_x86/vm/atomic_linux_x86.inline.hpp

看到了__asm__, 說明c++要開始內聯匯編了,說明繼續看代碼的話, 將會是匯編語言.

這是一段內聯匯編:

技術分享圖片

未完待續....困了睡.....

Java原子類中CAS的底層實現