[toc]java
什麼是原子性操做,按照官方的解析:原子操做不能在一箇中間操做中中止,要麼所有成功要麼所有失敗。(An atomic action cannot stop in the middle: it either happens completely, or it doesn't happen at all. No side effects of an atomic action are visible until the action is complete.),app
-- 除了long和double的讀寫,其餘的引用變量的讀寫操做都是原子性的 -- 若是加了volatile關鍵字,全部的引用變量的讀寫操做都是原子性的。 -- 原子操做不會被其餘的線程干擾。可是會存在內存不一致(consistency memory)的問題。可是使用關鍵字volatile能夠大大減小這個風險。 -- 線程修改volatile變量的時候,會在這個變量上面和其餘的讀取該變量的讀線程上面創建一個happens-before的關係。保證寫線程對該變量的修改對其餘的讀線程是可見的。ide
compare and swap.在一個內存地址V,一個指望值A,一個新值B。若是在V上面是指望的A值,那麼用B值去替換。不然經過自旋方式(死循環)一直到找到指望值位置。atom
傳統的鎖實現比較笨重,若是程序中須要對某些計算變量實現原子性,是用java的鎖會很笨重。並且給資源加鎖若是控制不得當的話,容易出現死鎖的現象。而CAS的出現就是爲了解決在無鎖的狀況下也能夠實現對於 資源的原子操做。
+ CAS容易產生ABA問題,就是一個內存地址V,值是A。有一個a線程要去修改它的值,此時有一個b線程把A的值改成了B,而後再改回A,此時對於a線程來講,它對於b線程的修改操做時無感知的。爲了解決ABA問題,引入了版本號。全部 線程修改一個內存的值前要先獲取值的版本號,修改完後須要更新版本號。這彷佛就須要使用AtomicStampedReference來操做了。若是是不關心值是否被修改過的狀況,不須要考慮ABA問題。 + 由於CAS會以自旋的方式索引指望值,若是一直沒有索引到指望值。爲了防止一直自旋下去,cpu會設置必定的閾值,超過閾值後就會掛起這個線程,讓出cpu。
/** * 演示帶版本Stamp的AtomicStampedReference使用 * compareAndSet方法,須要指定老的版本號,若是設置成功返回true,不然返回false * @author 45027056 * */ public class UseAtomicReferenceWithStamp { static String name = "luke"; AtomicStampedReference atomicStampedReference = new AtomicStampedReference(name,0); public static void main(String[] args) { UseAtomicReferenceWithStamp demo = new UseAtomicReferenceWithStamp(); demo.new SuccessThread().start(); de mo.new FailThread().start(); System.out.println("local name is...:"+ name); } class SuccessThread extends Thread{ int oldStamp = atomicStampedReference.getStamp(); String oldReferenct = (String) atomicStampedReference.getReference(); @Override public void run() { boolean result = atomicStampedReference.compareAndSet(oldReferenct, "joe1", 0, 1); System.out.println("refernce is :" + atomicStampedReference.getReference()); System.out.println("stamp is :" + atomicStampedReference.getStamp()); System.out.println("result is :" + result); } } class FailThread extends Thread{ int oldStamp = atomicStampedReference.getStamp(); String oldReferenct = (String) atomicStampedReference.getReference(); @Override public void run() { boolean result = atomicStampedReference.compareAndSet(oldReferenct, "joe2", 0, 1); System.out.println("refernce is" + atomicStampedReference.getReference()); System.out.println("stamp is" + atomicStampedReference.getStamp()); System.out.println("result is :" + result); } } }