volatile底层实现原理和其应用

volatile时轻量级的synchronized,它在多处理器开发中保证了数据的读的一致性,意思就是当一个线程修改一个共享变量时,另外一个线程能读到这个共享变量的值。如果volatile变量修饰符使用的恰当的话,他的运行成本会大大降低,因为他不会引起上下文的切换和调度,因为他并不会阻塞线程,也因此他不能保证多个线程对数据进行写操作时的安全性(即原子性)。

volatile不能保证原子性:

所谓原子性就是,要么都全部过程都执行成功,要么一个都执行不成功。

例如:i++这个操作分为三步

  1. 从内存中取出i
  2. 对i执行+1操作
  3. 将i放回内存中

当它只执行了前两步后就中断了,因此前两步执行成功,但是最后一步失败,i没有回滚减1,因此他不满足原子性,请看如下实例:

public abstract class Test {
	public static void main(String[] args) {
		 MyThread[] mythreadArray = new MyThread[100];
	        for (int i = 0; i < 100; i++) {
	            mythreadArray[i] = new MyThread();
	        }

	        for (int i = 0; i < 100; i++) {
	            mythreadArray[i].start();
	        }
	}
}
class MyThread extends Thread {
    public volatile static int count;

    private static void addCount() {
        for (int i = 0; i < 100; i++) {
            count++;
        }
        System.out.println("count=" + count);
    }

    @Override
    public void run() {
        addCount();
    }
}

结果:

volatile底层实现原理和其应用_第1张图片 

按理来说,他应该最后的输出结果时100*100的,这里说明了volatile并不能保证原子性。

那么volatile是怎么实现的呢?

先来看一下volitile的定义是什么,在JAVA语言规范第三版中对volatile的定义如下:Java编程语言允许多线程访问共享变量,为了确保共享变量能被准却和一致地更新 ,线程应该确保通过排他锁单独的获取这个变量。

他通过两步实现其功能:

1、线程通过调用cpu修改值之后,会将缓存行中的数据写回到内存中去。在执行写回操作时,处理器可以独占任何共享空间,而且最近的处理器,lock#信号不会锁总线,而是锁缓存,锁住总线的话,占用的资源太大。

2、写回操作会使在其他cpu里缓存了该内存地址的数据无效。例如在Pentium和P6 faminly处理器中,如果通过嗅探一个处理器来检测其他处理器打算写的内存地址,而这个地址处于共享状态,那么正在嗅探的处理器将会使其自身的缓存行无效,下次访问相同的内存地址时,强制执行缓存行填充。

 

你可能感兴趣的:(JAVA)