Java併發程式設計-原子操作的實現原理
阿新 • • 發佈:2018-12-27
原子(atomic)本意時“不能被進一步分割的最小粒子”,而原子操作(atomic operation)意為“不可被中斷的一個或一系列操作”。
Java 如何實現原子操作
在 Java 中可以通過鎖和迴圈 CAS 的方式實現原子操作。
1、使用迴圈 CAS 實現原子操作
JVM 中的 CAS 操作正是利用了處理器提供的 CMPXCHG 指令實現的。自旋 CAS 實現的基本思路就是迴圈進行 CAS 操作直到成功為止,以下程式碼實現了一個基於 CAS 執行緒安全的計數器方法 safeCount 和一個非執行緒安全的計數器 count。
import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; /** * Author: YiFan * Date: 2018/11/25 20:39 * Description: CAS操作 */ public class CASTest { private AtomicInteger atomicI = new AtomicInteger(0); private int i = 0; public static void main(String[] args) throws InterruptedException { final CASTest cas = new CASTest(); List<Thread> threads = new ArrayList<>(600); long start = System.currentTimeMillis(); for (int i = 0; i < 100; i++) { Thread t = new Thread(() -> { for (int j = 0; j < 10000; j++) { cas.count(); cas.safeCount(); } }); threads.add(t); } for (Thread t: threads ) { t.start(); } // 等待所有執行緒執行完成 for (Thread t: threads ) { t.join(); } System.out.println(cas.i); System.out.println(cas.atomicI.get()); System.out.println(System.currentTimeMillis() - start); } // 非執行緒安全計數器 private void count() { i++; } // 使用CAS實現執行緒安全計數器 private void safeCount() { for (;;) { int i = atomicI.get(); boolean suc = atomicI.compareAndSet(i, ++i); if (suc) { break; } } } }
該示例演示了多執行緒下對共享變數進行操作,count 方法中沒有使用 CAS 操作,導致多個執行緒可以同時對共享變數 i 進行操作,所以導致最終的 i 值不為 100000。但是 safeCount 方法中使用了 CAS 操作,這樣就解決的多執行緒下對 i++ 的原子性操作了,所以最終 i 值始終為 100000。
2、使用鎖機制實現原子操作
鎖機制保證了只有獲得鎖的執行緒才能夠操作鎖定的記憶體區域。JVM 內部實現了很多種鎖機制,有偏向鎖、輕量級鎖和互斥鎖。其中 JVM 實現鎖的方式都用了迴圈 CAS,即當一個執行緒想進入同步塊的時候使用迴圈 CAS 的方式來獲取鎖,當他退出同步塊的時候使用迴圈 CAS 釋放鎖。