package concurrent;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/*
* @author: wjf
* @version: 2016年3月26日 下午8:03:50
*/
public class TestVolatile {
// public volatile int inc=0;
public AtomicInteger inc=new AtomicInteger(0);
Lock lock=new ReentrantLock();
/*
* volatile 作用概述:可以保證可見性,一定程度上保證順序性,一定程度上避免指令重排,
* 例如:
* int x=1; // 1
* int y=2; //2
* volatile boolean flag=false; //3
* x=3; //4
* y=2; //5
* volatile 保證 1,2 在 3之前,4.5 在 3之後
* 並且 語句1,2 對3,4 是可見的。
*
* volatile 使用場景
* 1:標記狀態量
* volatile boolean flag=false;
* while(!flag){
* dosomething();
* }
* public void setFlag(){
* flag=true;
* }
*
* volatile boolean inited=false;
* 線程1
* cotext=loadContext();
* inited=true;
* 線程2
* while(!inited){
* sleep();
* }
* dosomethingwithconfig(context) // volatie 可以保證inited 在 context 執行完之後對inited 賦值
*
*2:double check
*
*/
/*
* volatile 可以保證可見性,當線程A 修改共享變量之後,會導致線程B 對共享變量的
* 緩存失效
* 但是卻無法保證原子性
* 首先明確一點:內存模型中 ,線程都有自己的工作內存(高速緩存),java 中每個變量都存在主存中
* 例如:i=1 執行線程必須先在自己的工作線程中對變量i 所在的緩存進行操作,然後寫入內存
* 例如:對於下面的例子,輸出結果可能小於10000
* 比如存在下面的調度順序:
* 1 A 讀取inc 的 值,然後被阻塞
* 2 B 讀取inc 的值,然後+1 ,然後被阻塞(沒有將inc 的值寫會,當然就沒有更新到內存中)
* 3 A 喚醒,inc+1,寫會,更新到內存中
* 4 B 喚醒,inc 值寫會,更新到內存(此時雖然inc 緩存的值已經失效,可是此時的B已經進行完了
* +1操作,只剩下把值寫會了)
*/
public void increase(){
// 使用 synchronized 解決這個問題
// synchronized (this){
// inc++;
// }
// 使用 lock 解決這個問題
// lock.lock();
// try{
// inc++;
// }finally{
// lock.unlock();
// }
// 使用AtomicInteger解決
inc.getAndIncrement();
}
public static void main(String[] args) {
// TODO Auto-generated method stub
final TestVolatile test=new TestVolatile();
for(int i=0;i<10;i++){
new Thread(){
public void run(){
for(int j=0;j<1000;j++){
test.increase();
}
}
}.start();
}
while(Thread.activeCount()>1){
Thread.yield();
}
System.out.println(test.inc);
}
}
java volatile 詳解
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.