Skip to content

Latest commit

 

History

History
117 lines (80 loc) · 3.23 KB

AtomicInteger.md

File metadata and controls

117 lines (80 loc) · 3.23 KB

無鎖的 Thread Safe 整數:AtomicInteger




為了讓 Java 使用者可以享用 CAS 等 CPU 指令,JDK 提供一個 atomic package,裡面實現了一些直接使用 CAS 操作的類別。

AtomicInteger 應該就算是最常用的一個類別,他是整數,但是與 Integer 不同,它是可變的(可以同步化,但沒必要),且是 Thread Safe。

列舉 AtomicInteger 的主要方法:


public final int get()                                  // 取得當前值
public final void set(int newVaule)                     // 設定當前值
public final int getAndSet(int newVaule)                // 設定新值,返回舊值
public final boolean compareAndSet(int expect, int n)   // 當前值為 expect 則設置為 n
public final int getAndIncrement()                      // 當前值 +1,返回舊值
public final int getAndDecrement()                      // 當前值 -1,返回舊值
public final int getAndAdd(int delta)                   // 當前值 + delta,返回舊值
public final int incrementAndGet()                      // 當前值 +1,返回新值
public final int decrementAndGet()                      // 當前值 -1,返回新值
public final int addAndGet(int delta)                   // 當前值 + delta,返回新值

AtomicInteger 內部有兩個重要 Field:


private volatile int value; // 當前值

private static final long valueOffset; // value 在 AtomicInteger 物件中的位置偏移量

AtomicInteger 的使用非常簡單:


public class AtomicIntegerDemo {

    static AtomicInteger integer = new AtomicInteger();

    public static class AddTask implements Runnable {

        @Override
        public void run() {
            for (int i = 0; i < 1000; ++i) {
                integer.incrementAndGet();  // #1
            }
        }

        public static void main(String[] args) {
            ExecutorService es = Executors.newFixedThreadPool(10);
            IntStream.range(0, 10).forEach(i -> {
                es.submit(new AddTask());
            });
            es.shutdown();
            while (integer.get() != 10000);
            System.out.println(integer);
        }
    }
}

#1 處的 incrementAndGet() 方法會使用 CAS 操作將自己 + 1,並返回當前值。

使用 AtomicInteger 比使用鎖來得好,這是一定的,看一下 incrementAndGet() 是如何實現的,這很有趣。


以下是 JDK 1.8 的實現:

public final int incrementAndGet() {
        return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
    }

public final int getAndAddInt(Object o, long offset, int delta) {
        int expect;
        do {
            expect = getIntVolatile(o, offset); // 期望值
        } while (!compareAndSwapInt(o, offset, expect, expect + delta)); // CAS,回傳 false 就重試,直到成功
        return expect;
    }

compareAndSwapInt() 一旦檢測到發生衝突(實際值與期望值不符)就回傳 false,這裡會用 while 迴圈重試 直到成功修改。





AtomicInteger 類似的還有:

  • AtomicLong(long)

  • AtomicBoolean(boolean)

  • AtomicReference(物件引用)