前言
java.util.concurrent.atomic 包下共有 17個類。統計代碼如下
public static void main(String[] args) throws IOException {
JarFile jarFile = new JarFile("/Library/Java/JavaVirtualMachines/jdk1.8.0_144.jdk/Contents/Home/jre/lib/rt.jar");
Enumeration<JarEntry> jarEntries = jarFile.entries();
AtomicInteger num = new AtomicInteger();
String packageStr = "java/util/concurrent/atomic";
jarFile.stream().forEach(m->{
if(m.getName().startsWith(packageStr) && !m.getName().contains("$") && m.getName().endsWith("class")){
System.out.println(m.getName().substring(m.getName().indexOf(packageStr)+packageStr.length()+1));
num.getAndIncrement();
}
});
System.out.println("共有類:"+num.toString());
結果如下:
包簡介
atmic 包主要支持單變量上的無鎖線程安全編程。
分類:
- 原子更新基本類型類
- AtomicBoolean:原子更新布爾類型。
- AtomicInteger:原子更新整型。
- AtomicLong:原子更新長整型。
- 原子更新數組類
- AtomicIntegerArray:原子更新整型數組裏的元素。
- AtomicLongArray:原子更新長整型數組裏的元素。
- AtomicReferenceArray:原子更新引用類型數組裏的元素。
- 原子更新引用類型
- AtomicReference:原子更新引用類型。
- AtomicReferenceFieldUpdater:原子更新引用類型裏的字段。
- AtomicIntegerFieldUpdater:原子更新整型的字段的更新器。
- AtomicLongFieldUpdater:原子更新長整型字段的更新器。
- AtomicStampedReference:原子更新帶有版本號的引用類型。該類將整數值與引用關聯起來,可用於原子的更數據和數據的版本號,可以解決使用CAS進行原子更新時,可能出現的ABA問題。
- 針對 Atomic 相關數字類的改進類
- LongAdder
- LongAccumulator
- DoubleAdder
- DoubleAccumulator
原子更新基本類型
AtomicBoolean
常用方法:
- public final boolean compareAndSet(boolean expect,
boolean update)
如果當前值 == 預期值,則以原子方式將該值設置爲給定的更新值。
參數:
expect - 預期值
update - 新值
返回:
如果成功,則返回 true。返回 False 指示實際值與預期值不相等。 - getAndSet
public final boolean getAndSet(boolean newValue)
以原子方式設置爲給定值,並返回以前的值。
參數:
newValue - 新值
返回:
以前的值
AtomicInteger
常用方法(如果涉及加減,則只列舉加):
- incrementAndGet 自增,返回最新的值
- addAndGet 做加法,並返回最新的值
- compareAndSet 設置值,並返回是否設置成功
AtomicLong
常用方法(如果涉及加減,則只列舉加):
- incrementAndGet 自增,返回最新的值
- addAndGet 做加法,並返回最新的值
- compareAndSet 設置值,並返回是否設置成功
原子更新數組類
注意:
- 原子更新數組類不會直接操作傳入的數組,而是操作自己 clone 的傳入的數組的副本
AtomicIntegerArray
常用方法:
- addAndGet(int i, int delta) cas 更新下標爲 i 的數字爲 當前數+delta,並返回最新值
- incrementAndGet(int i) cas 下標爲 i 的元素進行自增,並返回最新值
- compareAndSet(int i, int expect, int update) 比較下標爲 i 的元素和 expect,相等則更新爲 update,返回是否更新成功
AtomicLongArray
類似 AtomicIntegerArray
AtomicReferenceArray
常用方法:
- compareAndSet(int i, E expect, E update) 比較下標爲 i 的引用和 expect 是否相同,相同的話,則將引用更新爲 update。返回值爲是否更新
原子更新引用類型
AtomicReference
原子更新引用
AtomicReferenceFieldUpdater
原子更新引用對象字段。這個類是基於反射的一個工具類。被更新的字段需要滿足以下要求:
- 被 volatile 修飾(保證可見行)
- 不能被 private 修飾符修飾
核心方法:
- AtomicReferenceFieldUpdater<U,W> newUpdater(Class< U> tclass,
Class< W> vclass,
String fieldName) 生成一個更新器。 - compareAndSet(T obj, V expect, V update) 比較並跟新 obj 的字段值,並返回是否成功更新
使用示例:
@org.junit.Test
public void testAtomicReferenceFieldUpdater(){
Person person = new Person("小田切讓",20);
AtomicReferenceFieldUpdater fieldUpdater = AtomicReferenceFieldUpdater.newUpdater(Person.class,Integer.class,"age");
fieldUpdater.compareAndSet(person,person.getAge(),new Integer(33));
System.out.println(person.getAge());
}
@AllArgsConstructor
@Data
class Person{
private String name;
public volatile Integer age;
}
AtomicIntegerFieldUpdater
修改引用對象中被 int 修飾的字段。該字段必須滿足以下要求:
- 被 int 修飾,不能使用包裝類型 Integer 修飾
- 必須被 volatile 修飾
- 不能被 private 修飾
常用方法:
- newUpdater(Class tclass,String fieldName) 生成字段更新器
- incrementAndGet(T obj) obj 的字段自增,並返回最新值
- compareAndSet(T obj, int expect, int update)
示例:
@org.junit.Test
public void testAtomicIntegerFieldUpdater(){
Person person = new Person("小田切讓",new Integer(20));
AtomicIntegerFieldUpdater<Person> updater = AtomicIntegerFieldUpdater.newUpdater(Person.class,"age");
updater.incrementAndGet(person);
updater.compareAndSet(person,person.getAge(),new Integer(25));
System.out.println(person.getAge());
}
@AllArgsConstructor
@Data
class Person{
private String name;
public volatile int age;
}
AtomicLongFieldUpdater
類似 AtomicIntegerFieldUpdater ,修改引用對象中被 long 修飾的字段。該字段必須滿足以下要求:
- 被 long 修飾,不能使用包裝類型 Long 修飾
- 必須被 volatile 修飾
- 不能被 private 修飾
AtomicStampedReference
解決原子更新引用的「ABA」問題
常用方法:
- compareAndSet(V expectedReference,
V newReference,
int expectedStamp,
int newStamp) 比較引用和標誌,都相同才進行更新,並返回更新結果
示例:
@org.junit.Test
public void testAtomicStampedReference(){
Person person = new Person("小田切讓",20);
AtomicStampedReference<Person> reference = new AtomicStampedReference<>(person,100);
reference.compareAndSet(person,new Person("小栗旬",23),100,101);
System.out.println(reference.getReference().getName());
System.out.println(reference.getStamp());
}
針對 Atomic 相關數字類的改進類
LongAdder
針對 AtomicLong 的改進類,在高併發的情況下,擁有更好的表現
常用方法:
- add(long x) 加法
- increment() 自增
- decrement() 自減
DoubleAdder
常用方法:
- add(double x)
LongAccumulator
LongAdder 只提供了「加」操作,假如需要對當前結果 m 進行 m*5+1,這種複合運算,則需要 LongAccumulator。
ongAdder類是LongAccumulator的一個特例,LongAccumulator提供了比LongAdder更強大的功能,如下構造函數,其中accumulatorFunction是一個雙目運算器接口,根據輸入的兩個參數返回一個計算值(兩個參數分別代表,當前值,輸入值),identity則是LongAccumulator累加器的初始值。
常用方法:
- LongAccumulator(LongBinaryOperator accumulatorFunction,
long identity) - accumulate(long x) 進行一次計算
demo:
@org.junit.Test
public void testLongAccumulator(){
LongAccumulator longAccumulator = new LongAccumulator((m,n)-> {
return m*n+1; // 這裏結果其實是 100 * 10 +1
},100);
longAccumulator.accumulate(10);
System.out.println(longAccumulator.longValue());
}
DoubleAccumulator
類似 LongAccumulator