java.util.concurrent.atomic包一共提供了13個類。屬於4種類型的原子更新方式,分別是原子更新基本類型,原子更新數組,原子更新引用和原子更新屬性。Atomic包里的類基本都是使用Unsafe實現的包裝類。
原則更新基本類型
AtomicBoolean:原子更新布爾類型
AtomicInteger:原子更新整型
AtomicLong:原子更新長整型
這3個類提供的方法幾乎一樣,以AtomicInteger為例,常用方法如下:
int addAndGet(int delta):以原子方式將輸入的數值與實例中的值想加,並返回結果
boolean compareAndSet(int expect, int update):若輸入的數值等於預期值,則以原子方式將該值設置為輸入的值
int getAndIncrement():以原子方式將當前值加1,返回的是自增前的值
void lazySet(int newValue):最終會設置成new Value,使用lazySet設置后,可能會導致其他線程在之后的一小段時間內還是可以讀到舊的值
int getAndSet(int newValue):以原子方式設置為newValue的值,並返回舊值
public final int getAndIncrement(){ for(;;){ int current = get(); int next = current + 1; if(compareAndSet(current, next)) return current; } } public final boolean compareAndSet(int expext, int update){ return unsafe.compareAndSwapInt(this, valueOffset, expect, update); }
public interface Unsafe{
public final native boolean compareAndSwapObject(Object o, long offset, Object expected, Object x);
public final native boolean compareAndSwapInt(Object o, long offset, int expected, int x); public final native boolean compareAndSwapLong(Object o, long offset, long expectd, long x);
}
原子更新數組
AtomicIntegerArray:原子更新整形數組里的元素
AtomicLongArray:原子更新長整型數組里的元素
AtomicReferenceArray:原子更新引用類型數組里的元素
上述幾個類提供的方法幾乎一致,以AtomicIntegerArray為例:
int addAndGet(int i. int delta):以原子方式將輸入值與數組中索引i的元素想加
boolean compareAndSet(int i. int expect, int update):若當前值等於預期值,則以原子方式將數組位置i的元素設置成update值
原子更新引用類型
需要原子更新多個變量可以使用原子更新引用類型提供的類。
AtomicReferemce:原子更新引用類型
AtomicReferenceFieldUpdater:原子更新引用類型里的字段
AtomicMarkableReference:原子更新帶有標記位的引用類型。可以原子更新一個布爾類型的標記位和引用類型。構造方式是AtomicMarkableReference(V initialRef, boolean initialMark)。
public class AtomicReferenceTest{ public static AtomicReference<User> atomicUserRef = new AtomicReference<User>(); public static void main(String args[]){ User user = new User("conan", 15); atomicUserRef.set(user); User updateUser = new User("Shinichi", 17); atomicUserRef.compareAndSET(user, updateUser); System.out.println(atomicUserRef.get().getName()); // Shinichi System.out.println(atomicUserRef.get().getOld()); // 17 } static class User{ private String name; private int old; public User(String name, int old){ this.name = name; this.old = old; } public String getName(){ return name; } public int getOld(){ return old; } } }
原子更新字段類
若需要原子地更新某個類里面的某個字段時,就需要使用原子更新字段類。
AtomicIntegerFieldUpdater:原子更新整型的字段的更新器
AtomicLongFieldUpdater:原子更新長整型字段的更新器
AtomicStampedReference:原子更新帶有版本號的引用類型。該類將整數值與引用關聯起來,可用於原子的更新數據和數據的版本號,可以解決使用CAS進行原子更新時可能出現的ABA問題
使用原子更新字段類需要兩步:因為原子更新字段類都是抽象類,每次使用時必須使用靜態方法newUpdater()創建一個更新器,並且需要設置想要跟新的類和屬性。第二步更新類的字段(屬性)必須使用public volatile修飾符。
以上3個類提供的方法幾乎一樣,所以以AtomicIntegerFieldUpdater為例
public class AtomicIntegerFieldUpdaterTest{ private static AtomicIntegerFieldUpdater<User> a = AtomicIntegerFieldUpdater.newUpdater(User.class. "old");
public static void main(String[] args){ User conan = new User("conan", 10); System.out.println(a.getAndIncrement(conan)); // 10 System.out.println(a.get(conan)); // 11 }
static class User{
private String name; public volatile int old; //一定要用public volatile修飾 public User(String name, int old){ this.name = name; this.old = old; } public String getName(){ return name; } public int getOld(){ return old; } }
}