volitale 關鍵字他是不具備原子性的,但是Atomic XXX 都是具備原子性操作
public static void main(String[] args) {
//AtomicInteger
AtomicInteger atomicInteger = new AtomicInteger();
System.out.println(atomicInteger.get()); // 結果 0
atomicInteger = new AtomicInteger(10);
System.out.println(atomicInteger.get()); // 10
atomicInteger.set(20);
System.out.println(atomicInteger.get()); // 20
int sum = atomicInteger.getAndAdd(30);
System.out.println(sum); // 20
System.out.println(atomicInteger.get()); // 通過get菜可以得到值
//AtomicBoolean AtomicLong .. 等等都和上面使用差不多
}
AtomicReference
包裝對象爲原子性操作
CAS 會引起 ABA問題
摘抄自:https://www.cnblogs.com/androidsuperman/p/9249180.html
CAS需要在操作值的時候檢查下值有沒有發生變化,如果沒有發生變化則更新,但是如果一個值原來是A,變成了B,又變成了A,那麼使用CAS進行檢查時會發現它的值沒有發生變化,但是實際上卻變化了。ABA問題的解決思路就是使用版本號。在變量前面追加上版本號,每次變量更新的時候把版本號加一,那麼A-B-A 就會變成1A-2B-3A。 從Java1.5開始JDK的atomic包裏提供了一個類AtomicStampedReference
來解決ABA問題。這個類的compareAndSet方法作用是首先檢查當前引用是否等於預期引用,並且當前標誌是否等於預期標誌,如果全部相等,則以原子方式將該引用和該標誌的值設置爲給定的更新值。
AtomicStampedReference<Integer> stampedReference = new AtomicStampedReference<>(100,0); stampedReference.compareAndSet(100,0,stampedReference.getStamp(),stampedReference.getStamp()+1);
下面 AtomicIntegerArray、 AtomicLongArray、 AtomicReferenceArray 效果和用法等同於上面
AtomicIntegerFieldUpdater、AtomicLongFieldUpdater、AtomicReferenceFieldUpdater
對操作對象添加原子性操作
public class Test {
public static void main(String[] args) {
// 這個操作,會對age屬性添加原子性操作
final AtomicIntegerFieldUpdater fieldUpdater = AtomicIntegerFieldUpdater.newUpdater(Student.class,"age");
Student student = new Student();
fieldUpdater.compareAndSet(student,0,1);
// 上面這個操作需注意,可能會出現以下錯誤
/**
* 1,privateFieldAccessError // 屬性私有化
* 2,TargetObjectIsNull // student 換成null 報這個錯誤
* 3,fieldNameInvalid
*/
}
}
@Data
class Student{
volatile int age;
}
unsafe 類圖
略