(6)Atomic類原子操作

    對於簡單的計數和加減操作,lock和synchronized的鎖粒度太大,容易導致高併發時效率問題。J.U.C包中提供了一個更加高效的解決方案——Atomic類。它的底層通過CAS操作來實現併發安全性。

    Atomic類裏提供了4種操作對象,下面分別介紹。

一、 基本原子類型

  AtomicBoolean

  AtomicInteger

  AtomicLong

  以AtomicInteger爲例,他們常用的方法

getAndIncrement

先返回原值,再+1
incrementAndGet 先+1,再返回+1後的值

getAndDecrement

先返回原值,再-1
decrementAndGet 先-1,再返回-1後的值
addAndget(int value) 先+value,然後返回計算的值

getAndAdd(int value)

先返回原值,然後將原值+value
compareAndSet(e, n)

原值若是期望值e就設置爲新值new,返回true;

否則,就不更改,返回false 

accumulateAndGet(x, IntBinaryOperator  function)

使用當前值與 x 進行function計算,並將計算結果返回
getAndaccumulate(x, IntBinaryOperator function) 先返回當前值,然後將當前值與x進行function計算,結果存爲新值

前面的都比較好理解,這裏就舉最後兩個的例子:

AtomicInteger a = new AtomicInteger(2);
System.out.println(a.getAndAccumulate(5, Math::max));   //2   ,先返回後計算max(a, 5)
System.out.println(a);   //5  ,max(a,5)之後的值存入了a

System.out.println(a.accumulateAndGet(10, Math::max));  //10
System.out.println(a);   //10

二、原子數組

  原子數組就是可以聲明原子變量的數組,然後對這個數組的各個變量進行原子操作。

int[] data = {1,2,3,4};
AtomicIntegerArray array = new AtomicIntegerArray(data);
System.out.println(array.getAndSet(1, 10));     //對[1]的數設置爲10
System.out.println(array.get(1));               //10

   它的方法與基本原子類型基本相同,只是操作的時候第一個操作數是數組的下標。

三、原子抽象類型

  我們可以對一個類的對象進行原子操作,方法就是用到AtomicReference<>

public class User {
    public volatile int age;

    public User(int age) {
        this.age = age;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

public static void main(){
    AtomicReference<User> user = new AtomicReference<>();  //聲明User爲原子抽象類型
    System.out.println(user);         //null
    User user1 = new User(10);
    System.out.println(user1);       //User@74a14482
    user.getAndSet(user1);                                 //對user對象進行原子操作
    System.out.println(user);        //User@74a14482,與user1相同
}

    需要說明的是, User類爲原子抽象類型,指我們可以對User類的對象進行原子操作,而不是我們可以對User類中的一個屬性變量可以原子操作(如 int age, 是不能原子操作的)。能對其進行操作的是下一個——原子字段。

 

四、原子(抽象類型)字段

  原子字段是指對一個類中的某一個字段進行原子操作。

public static void main(){
    User user = new User(15);
    //將User.class 中的 "age"字段聲明爲原子字段
    AtomicIntegerFieldUpdater<User> data = AtomicIntegerFieldUpdater.newUpdater(User.class, "age");
    data.set(user, 25);   //設置時需要指明對象

    new Thread(new Runnable() {
        @Override
        public void run() {
            System.out.println(data.getAndIncrement(user));  //25
            System.out.println(data.get(user));              //26
        }
    }).start();

}

  因爲進行原子操作的是類實例中的一個字段,所以操作的時候需要指明操作實例。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章