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

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