文章目錄
atomic包
java.util.concurrent.atomic
包下的類大多是使用CAS操作來實現的(eg.AtomicInteger.java,AtomicBoolean,AtomicLong
)。下面以AtomicInteger.java
的部分實現來大致講解下這些原子類的實現。
它提供了原子自增方法、原子自減方法以及原子賦值方法等
public class AtomicInteger extends Number implements java.io.Serializable {
private static final long serialVersionUID = 6214790243416807050L;
// setup to use Unsafe.compareAndSwapInt for updates
private static final Unsafe unsafe = Unsafe.getUnsafe();
private volatile int value;// 初始int大小
// 省略了部分代碼...
// 帶參數構造函數,可設置初始int大小
public AtomicInteger(int initialValue) {
value = initialValue;
}
// 不帶參數構造函數,初始int大小爲0
public AtomicInteger() {
}
// 獲取當前值
public final int get() {
return value;
}
// 設置值爲 newValue
public final void set(int newValue) {
value = newValue;
}
//返回舊值,並設置新值爲 newValue
public final int getAndSet(int newValue) {
/**
* 這裏使用for循環不斷通過CAS操作來設置新值
* CAS實現和加鎖實現的關係有點類似樂觀鎖和悲觀鎖的關係
* */
for (;;) {
int current = get();
if (compareAndSet(current, newValue))
return current;
}
}
// 原子的設置新值爲update, expect爲期望的當前的值
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
// 獲取當前值current,並設置新值爲current+1
public final int getAndIncrement() {
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return current;
}
}
// 此處省略部分代碼,餘下的代碼大致實現原理都是類似的
}
一般來說在競爭不是特別激烈的時候,使用該包下的
原子操作性能比使用 synchronized 關鍵字的方式高效的多(查看getAndSet()
,可知如果資源競爭十分激烈的話,這個for循環可能換持續很久都不能成功跳出。不過這種情況可能需要考慮降低資源競爭纔是)。
在較多的場景我們都可能會使用到這些原子類操作。一個典型應用就是計數了,在多線程的情況下需要考慮線程安全問題
。通常第一映像可能就是:
public class Counter {
///這個版本是線程安全的
private int count;
public Counter(){}
public int getCount(){
return count;
}
public void increase(){
count++;
}
}
上面這個類在多線程環境下會有線程安全問題,要解決這個問題最簡單的方式可能就是通過加鎖的方式,調整如下:
public class Counter {
private int count;
public Counter(){}
public synchronized int getCount(){
return count;
}
public synchronized void increase(){
count++;
}
}
這類似於悲觀鎖的實現,我需要獲取這個資源,那麼我就給他加鎖,別的線程都無法訪問該資源,直到我操作完後釋放對該資源的鎖。我們知道,悲觀鎖的效率是不如樂觀鎖的,上面說了Atomic下的原子類的實現是類似樂觀鎖的,效率會比使用 synchronized 關係字高,推薦使用這種方式,實現如下:
public class Counter {
private AtomicInteger count = new AtomicInteger();
public Counter(){}
public int getCount(){
return count.get();
}
public void increase(){
count.getAndIncrement();
}
}