先看一個使用volatile的例子
public class VolatileTest {
public static volatile int race=0;
public static void increase(){
race++;
}
private static final int THREADS_COUNT=20;
public static void main(String[] args){
Thread[] threads=new Thread[THREADS_COUNT];
for(int i=0;i
threads[i]=new Thread(new Runnable(){
public void run(){
for(int i=0;i<10000;i++){
increase();
}
}
});
threads[i].start();
}
while(Thread.activeCount()>1)
Thread.yield();
System.out.println(race);
}
}
預期輸出200000
但是實際輸出總是小於200000
如148407
原因:volatile變量只能保證可見性
主要用於下列場景:
1、運算結果不依賴變量的當前值
2、變量不需要與其他變量共同參與不變約束
改進方法
使用CAS指令
CAS中有三個操作樹,分別是內存位置V、舊的預期值A、新值B
當且僅當V符合A時,處理器才用B更新V
不論更新成功與否返回值均為V(更新前的值)
此指令的操作是原子操作
public class AtomicTest {
public static AtomicInteger race = new AtomicInteger(0);
public static void increase() {
race.incrementAndGet();
}
private static final int THREADS_COUNT = 20;
public static void main(String[] args) {
Thread[] threads = new Thread[THREADS_COUNT];
for (int i = 0; i < THREADS_COUNT; i++) {
threads[i] = new Thread(new Runnable() {
public void run() {
for (int i = 0; i < 10000; i++) {
increase();
}
}
});
threads[i].start();
}
while (Thread.activeCount() > 1)
Thread.yield();
System.out.println(race);
}
}
輸出:200000
看下incrementAndGet的實現
/**
* Atomically increments by one the current value.
*
* @return the updated value
*/
public final int incrementAndGet() {
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return next;
}
}
再看下compareAndSet的實現
/**
* Atomically sets the value to the given updated value
* if the current value {@code ==} the expected value.
*
* @param expect the expected value
* @param update the new value
* @return true if successful. False return indicates that
* the actual value was not equal to the expected value.
*/
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
遺留問題:“ABA”問題
概率低,可以使用傳統的互斥同步方法解決
參考:
深入理解Java虛擬機:JVM高級特性與最佳實踐, 作者: 周志明, 品牌: 機械工業出版社, 版本: 第1版, 機械工業出版社