1. 程式人生 > >原子性 CAS演算法

原子性 CAS演算法

一、 i++ 的原子性問題

1、問題的引入:

i++ 的實際操作分為三個步驟:讀--改--寫

實現執行緒,程式碼如下:

public class AtomicDemo implements Runnable
{
    private int serialNumber = 0;

    @Override
    public void run()
    {
        try
        {
            Thread.sleep(400);
        }
        catch (InterruptedException e)
        {}
        System.out.println(Thread.currentThread().getName() 
+ ": " + this.getSerialNumber()); } public int getSerialNumber() { return serialNumber++; } }

測試類,程式碼如下:

public class AtomicTest
{
    public static void main(String[] args)
    {
        AtomicDemo atomicDemo = new AtomicDemo();
        for (int i = 0; i < 10; i++)
        {
            
new Thread(atomicDemo).start(); } } }

結果如下圖所示:

 

以上的原子性問題可以使用“原子變數”解決;

二、原子變數

在JDK1.5 之後,提供了 java.util.concurrent.atomic 包下提供了常用的原子變數;

 AtomicBoolean、AtomicInteger、AtomicIntegerArray、AtomicIntegerFieldUpdater、AtomicLong、AtomicReference 等

從以上類原始碼中可以看出:

  (1)變數使用了 Volatile 修飾,保證了記憶體可見性;

  (2)使用了 CAS(Compare-And-Swap)演算法,保證了資料的原子性;

  CAS演算法是硬體對於併發操作共享資料的支援;

  CAS 包含了三個運算元:記憶體值 、預估值 、更新值 ;

    當且僅當記憶體值等於預估值時,把更新值賦給記憶體值,否則將不做任何操作;

class AtomicDemo implements Runnable
{
    private AtomicInteger serialNumber = new AtomicInteger();

    @Override
    public void run()
    {
        try
        {
            Thread.sleep(400);
        }
        catch (InterruptedException e)
        {}
        System.out.println(Thread.currentThread().getName() + ": " + this.getSerialNumber());
    }

    public int getSerialNumber()
    {
        return serialNumber.getAndIncrement();
    }
}