原子性 CAS演算法
阿新 • • 發佈:2018-12-13
一、 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();
}
}