volatile关键字解释

引入的原因:

  1. 线程间通信可以使用共享变量的方式(一块公共内存)
  2. 现代计算机都是多cpu的,并且为了提高效率,cpu都是带缓存的,并且设计成分层的,有一级缓存、二级缓存、三级缓存(L1,L2,L3)。每个cpu有自己的cache
    L1响应时间1ns,3个时钟周期,大小32K
    L2响应时间3ns,大小256K
    L3响应时间12ns,大小8M
    直接访问主内存的响应时间65ns
    为什么设计这么复杂,还分层?
    就是考虑成本的问题,最近也看到新闻说内存涨价了,如果不考虑成本那就简单了,直接都怼上最贵的L1cache,就不需要开发人员考虑这么多细节了。
    实际上一些应用程序最热的数据也就是那么几K,分层的目的也就是这个原因。

有以上是背景,在两个线程访问的时候,如果是不同的cpu执行这两个线程,就会出现缓存不一致问题。

volatile的作用

  1. 被volatile修饰的变量,jvm会做一些底层的工作,保证写入的操作,把更改后的内容立刻从cpu缓存回写到主内存。
  2. 保证了读的可见性,当一个线程读到被volatile修饰的变量的时候,会抛弃cpu缓存的值,从主内存复制一份到cpu缓存内,读取。保证读取得是最新的值。

synchronized和volatile作用的异同
当使用synchronized加锁的方式,也可以实现多线程下可见性。还能保证写入的原子性。
但是volatile不能保证多线程下操作的原子性。如下面例子

public class Test {
    public volatile int inc = 0;
     
    public void increase() {
        inc++;
    }
     
    public static void main(String[] args) {
        final Test test = new Test();
        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);
    }
}

要保证操作的原子性,处理synchronized关键字和lock外,还可以使用concurrent包下的AtomicInteger原子操作类,原来是利用硬件的原子操作指令cap。

volatile使用场景

volatile boolean inited = false;
//线程1:
context = loadContext();  
inited = true;            
 
//线程2:
while(!inited ){
sleep()
}
doSomethingwithconfig(context);

不使用volatile,会有概率出错。
没有使用锁是因为,volatile性能更高。

参考:http://www.cnblogs.com/dolphin0520/p/3920373.html

你可能感兴趣的:(volatile关键字解释)