线程笔记-volatile

本文详细解析了Intel MESI缓存一致性协议的工作原理,并深入介绍了volatile关键字的作用及其实现机制,包括保证可见性和禁止指令重排序等特性。

缓存一致性协议:最出名的就是Intel 的MESI协议,MESI协议保证了每个缓存中使用的共享变量的副本是一致的。它核心的思想是:当CPU写数据时,如果发现操作的变量是共享变量,即在其他CPU中也存在该变量的副本,会发出信号通知其他CPU将该变量的缓存行置为无效状态,因此当其他CPU需要读取这个变量时,发现自己缓存中缓存该变量的缓存行是无效的,那么它就会从内存重新读取。

volatile:当一个共享变量被volatile修饰时,它会保证修改的值会立即被更新到主存,当有其他线程需要读取时,它会去内存中读取新值。

  一旦一个共享变量(类的成员变量、类的静态成员变量)被volatile修饰之后,那么就具备了两层语义:
  1)保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。
  2)禁止进行指令重排序。  
在有限的一些情形下使用 volatile 变量替代锁。要使 volatile 变量提供理想的线程安全,必须同时满足下面两个条件:
1)对变量的写操作不依赖于当前值。
2)该变量没有包含在具有其他变量的不变式中。


package thread.basic._volatile.demo2;

public class Volatile2 extends Object implements Runnable {
    //value变量没有被标记为volatile
    private int value;  
    //missedIt变量被标记为volatile
    private volatile boolean missedIt;
    public Volatile2() {
        value = 0;
        missedIt = false;
    }

    public void run() {
        System.out.println(Thread.currentThread().toString()+"..entering run()");
        //循环检查value的值是否不同
        while ( missedIt ) {
            System.out.println(Thread.currentThread().toString()+"..printing..."+value++);
        }
        System.out.println(Thread.currentThread().toString()+"..leaving run()");
    }

    public void setStop(){
        missedIt = false;
    }
    public void setStart(){
        missedIt = true;
    }

    public static void main(String[] args) {
        try {
            //通过该构造函数可以获取实时时钟的当前时间
            Volatile2 vol = new Volatile2();
            Thread t = new Thread(vol);
            Thread t2 = new Thread(vol);
            Thread t3 = new Thread(vol);
            vol.setStart();  //设置关闭
            t.start();
//          Thread.sleep(10);  
//          vol.setStop();
            t2.start();
            Thread.sleep(10);  
            vol.setStop();
            t3.start();

        } catch ( InterruptedException x ) {
            System.err.println("one of the sleeps was interrupted");
        }
    }
}

volatile的原理和实现机制
  前面讲述了源于volatile关键字的一些使用,下面我们来探讨一下volatile到底如何保证可见性和禁止指令重排序的。
  下面这段话摘自《深入理解Java虚拟机》:
  “观察加入volatile关键字和没有加入volatile关键字时所生成的汇编代码发现,加入volatile关键字时,会多出一个lock前缀指令”
  lock前缀指令实际上相当于一个内存屏障(也成内存栅栏),内存屏障会提供3个功能:
  1)它确保指令重排序时不会把其后面的指令排到内存屏障之前的位置,也不会把前面的指令排到内存屏障的后面;即在执行到内存屏障这句指令时,在它前面的操作已经全部完成;
  2)它会强制将对缓存的修改操作立即写入主存;
  3)如果是写操作,它会导致其他CPU中对应的缓存行无效。
**注意:**volatile通常某个操作的完成、发生中断或状态的标示,不能确保操作的原值行(例如:i++)。
单例设计模式:

class Singleton{ 
    private volatile static Singleton instance = null; 

    private Singleton() { 

    } 
    public static Singleton getInstance() { 
        if(instance==null) { 
            synchronized (Singleton.class) { 
                if(instance==null) 
                    instance = new Singleton(); 
            } 
        } 
        return instance; 
    } 
} 

参考:http://www.cnblogs.com/dolphin0520/p/3920373.html
http://www.ibm.com/developerworks/cn/java/j-jtp06197.html
经典:http://blog.youkuaiyun.com/wxwzy738/article/details/43238089

volatile与static的区别
参考:http://blog.sina.com.cn/s/blog_4e1e357d0101i486.html

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值