Java原子類中CAS的底層實現
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的底層實現