java volatile 詳解

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);
    }

}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章