無鎖機制下的原子性操作
阿新 • • 發佈:2018-01-06
true setname boolean cnblogs 添加 amp 硬件 rfi tom
通常使用volatile關鍵字修飾字段可以實現多個線程的可見性和讀寫的原子性,但是對於字段的復雜性操作就需要使用synchronize關鍵字來進行,例如:
public class Counter { private volatile int count = 0; public synchronized int getAndIncr() { return this.count ++; } }
這裏可以看到,對於字段的簡單設置和獲取,volatile可以應付,但是我們想每次獲取後自增加1,這樣的操作就只能交給synchronize來做,這樣做雖然可以但是性能較低,所以我們這裏介紹一種新的無鎖操作CAS。
什麽是CAS(Compare And Swap)
比較並且交換內存地址的數據,由CPU在指令級別上進行操作的原子性。
CAS包含三個參數:1、變量所在的地址A 2、變量應該的值V1 3、我們需要改的值V2。
如果說變量地址A上的值為V1,就用V2進行復制;如果值不是V1,則什麽都不操作,返回V1的值。
自旋操作:在一個死循環裏不停的進行CAS的操作,直到成功為止。
CAS實現原子操作的三大問題
- 當線程想把地址A的值V1改為V3時,當線程取到V1的值後再進行比較時,地址A的值從V1->V2->V1進行了改變,雖然V3可以正常賦值,但是比較的V1值已經不是取出來的V1了。
- 循環時間很長的話,CPU的負荷較大。
- 對一個變量進行操作可以,同時操作多個共享的變量有些麻煩。
CAS線程安全
通過硬件層面的阻塞實現原子操作的安全性。
常用的原子操作類
- 更新基本類型類:AtomicBoolean,AtomicInteger,AtomicLong,AtomicReference
- 更新數組類:AtomicIntegerArray,AtomicLongArray,AtomicReferenceArray
- 更新引用類:AtomicReference,AtomicReferenceFieldUpdater,AtomicMarkableReference
- 原子更新字段類:AtomicIntegerFieldUpdater,AtomicLongFieldUpdater,AtomicStampedReference
public class AtomicArray { static int[] value = new int[]{1, 2}; static AtomicIntegerArray aia = new AtomicIntegerArray(value); public static void main(String[] args) { aia.set(0, 3); System.out.println(aia.get(0)); System.out.println(value[0]); } }
輸出:
3 1
可以看出AtomicIntegerArray對象將int數組復制了一份,他的改變並沒有影響到原有數組。
public class AtomicRef { static class User { private String name; private int age; public User(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } } static AtomicReference<User> userAtomicRef = new AtomicReference<AtomicRef.User>(); public static void main(String[] args) { User user = new User("Mark", 25); userAtomicRef.set(user); User updUser = new User("Mark", 28); userAtomicRef.compareAndSet(user, updUser); System.out.println(userAtomicRef.get().getName()); System.out.println(userAtomicRef.get().getAge()); } }
輸出:
Mark 28
這裏會首先進行比較,然後更新不一樣的字段。
這裏對CAS三大問題的第一個問題進行解決:
AtomicMarkableReference這個類會在數據被修改之後,標記位會由true變為false,判斷這個標記位就可得知。
AtomicStampedReference這個類會在數據上添加時間戳,如果有數據修改時間戳會變掉,從而判斷數據是否被修改。
本文索引關鍵字:
CAS:http://www.cnblogs.com/huanStephen/p/8213678.html#CAS
歡迎大家索引!
無鎖機制下的原子性操作