天天看點

Java中的Atomic包使用指南

​ Java從JDK 1.5開始提供了java.util.concurrent.atomic包(以下簡稱Atomic包),這個包中的原子操作類提供了一種用法簡單、性能高效、線程安全地更新一個變量的方式。在Atomic包裡一共提供了13個類,屬于4種類型的原子更新方式,分别是原子更新基本類型、原子更新數組、原子更新引用和原子更新屬性(字段)。

Atomic實作原理

CAS (compare and swap) + volatile和native方法

原子更新基本類型類

​ Atomic包提供了以下3個類:

  • AtomicBoolean:原子更新布爾類型;
  • AtomicInteger:原子更新整型;
  • AtomicLong:原子更新長整型。
//以原子方式将輸入的數值與執行個體中的值(AtomicInteger裡的value)相加,并傳回結果。
int addAndGet(int delta)
//如果輸入的數值等于預期值,則以原子方式将該值設定為輸入的值。
boolean compareAndSet(int expect,int update)
//以原子方式将目前值加1,注意,這裡傳回的是自增前的值。
int getAndIncrement()
//最終會設定成newValue,使用lazySet設定值後,可能導緻其他線程在之後的一小段時間内還是可以讀到舊的值。
void lazySet(int newValue)
//以原子方式設定為newValue的值,并傳回舊值。
int getAndSet(int newValue)

           

原子更新數組

Atomic包提供了以下4個類 :*

  • AtomicIntegerArray:原子更新整型數組裡的元素;
  • AtomicLongArray:原子更新長整型數組裡的元素;
  • AtomicReferenceArray:原子更新引用類型數組裡的元素;
  • AtomicIntegerArray類主要是提供原子的方式更新數組裡的整型。
//以原子方式将輸入值與數組中索引i的元素相加
int addAndGet(int i,int delta)
//如果目前值等于預期值,則以原子方式将數組位置i的元素設定成update值
boolean compareAndSet(int i,int expect,int update)
           

原子更新引用類型

​ 原子更新基本類型的AtomicInteger,隻能更新一個變量,如果要原子更新多個變量,就需要使用這個原子更新引用類型提供的類。Atomic包提供了以下3個類:AtomicReference:原子更新引用類型,AtomicReferenceFieldUpdater:原子更新引用類型裡的字段 ,AtomicMarkableReference :原子更新帶有标記位的引用類型。

原子更新字段類

​ 如果需原子地更新某個類裡的某個字段時,就需要使用原子更新字段類,Atomic包提供了以下3個類進行原子字段更新:AtomicIntegerFieldUpdater:原子更新整型的字段的更新器,AtomicLongFieldUpdater:原子更新長整型字段的更新器,AtomicStampedReference:原子更新帶有版本号的引用類型。

​ 要想原子地更新字段類需要兩步。第一步,因為原子更新字段類都是抽象類,每次使用的時候必須使用靜态方法newUpdater()建立一個更新器,并且需要設定想要更新的類和屬性。第二步,更新類的字段(屬性)必須使用public volatile修飾符。

import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
public class AtomicIntegerFieldUpdaterTest {
    // 建立原子更新器,并設定需要更新的對象類和對象的屬性
    private static AtomicIntegerFieldUpdater<User> a = AtomicIntegerFieldUpdater.newUpdater(User.class, "old");
    public static void main(String[] args) {
        // 設定柯南的年齡是10歲
        User conan = new User("conan", 10);
        // 柯南長了一歲,但是仍然會輸出舊的年齡
        System.out.println(a.getAndIncrement(conan));
        // 輸出柯南現在的年齡
        System.out.println(a.get(conan));
    }
    static class User {
        private String name;
        public volatile int old;
        public User(String name, int old) {
            this.name = name;
            this.old = old;
        }
        public String getName() {
            return name;
        }
        public int getOld() {
            return old;
        }
    }
}
           

問題:

1、volatile boolean和AtomicBoolean的差別?

答案:

https://codeday.me/bug/20170421/10912.html