volatile關鍵字的作用是保證可見性,但是不保證原子性。
可見性:在java多線程讀寫數據的時候,有兩塊區域,一塊是內存區,另一塊是線程內存緩衝區,當多線程訪問資源時,是先將資源在內存中拷貝到內存緩衝區。volatile可見性是指保證當線程裏對資源副本進行修改時,資源主動保存到內存庫。
原子性:是指操作的不可分割性。比如 a=0;(a非long和double類型) 這個操作是不可分割的,那麼我們說這個操作時原子操作。再比如:a++; 這個操作實際是a = a + 1;是可分割的,所以他不是一個原子操作。
volatile最典型的應用應該是單例模型中的雙重檢查索機制,如下面的例子。
public class Singleton {
private static Singleton uniqueInstance;
private Singleton(){
}
public static Singleton getInstance(){
if(uniqueInstance == null){ //#1
synchronized(Singleton.class){ //#2
if(uniqueInstance == null){ //#3
uniqueInstance = new Singleton(); //#4
System.out.println(Thread.currentThread().getName() + ": uniqueInstance is initalized..."); //#5.1
} else {
System.out.println(Thread.currentThread().getName() + ": uniqueInstance is not null now..."); //#5.2
}
}
}
return uniqueInstance;
}
}
接下來是TestSingleton類
public class TestSingleton {
public static void main(final String[] args) throws InterruptedException {
for (int i = 1; i <= 100000; i++) {
final Thread t1 = new Thread(new ThreadSingleton());
t1.setName("thread" + i);
t1.start();
}
}
public static class ThreadSingleton implements Runnable {
@Override
public void run() {
Singleton.getInstance();
}
}
}
如果對於單例對象uniqueInstance不增加violatile關鍵字,
則有可能出現初始化執行兩次的問題。