码迷,mamicode.com
首页 > 其他好文 > 详细

jvm-volatile

时间:2017-10-02 18:53:18      阅读:179      评论:0      收藏:0      [点我收藏+]

标签:idt   rup   top   ide   产生   多级   table   png   vol   

我们都知道volatile为共享变量提供了可见性,下面就来分析这种可见性是如何实现的。

在说volatile之前,首先需要引入一个概念:缓存行。为了增加cpu的访存速度,通常会在cpu和内存之间增加多级缓存,如下图,L1、L2都是核心独享的缓存,L3为单个插槽上所有cpu共享的缓存,MainMemory为所有cpu共享。

技术分享

 

根据局部性原理,cpu每次访问主存时都会读取至少一个缓存行的数据(通常一个缓存行为64字节,哪怕读取4字节数据,也会连续读取该数据之后的60字节),这里省略了多级缓存。

技术分享

 

下面来做一个测试,两个线程分别对一个共享int变量进行10000000次++操作,最终的输出大概率小于20000000且大于10000000,这说明JMM对共享变量的更新操作的逻辑是,先同步会主存,然后再从主存读取该共享变量。

 1     private int i = 0;
 2     @Test
 3     public void testIPlusPlus() throws InterruptedException {
 4         CountDownLatch countDownLatch = new CountDownLatch(2);
 5         class Task implements Runnable {
 6 
 7             @Override
 8             public void run() {
 9                 for(int j=0; j<10000000; j++) {
10                     i++;
11                 }
12                 countDownLatch.countDown();
13             }
14         }
15         new Thread(new Task()).start();
16         new Thread(new Task()).start();
17         countDownLatch.await();
18         System.out.println(i);
19     }

 

说了这么多,现在来看volatile。

Java代码: instance = new Singleton();//instance是volatile变量
汇编代码:

movb $0x0,0x1104800(%esi);

lock addl $0x0,(%esp);

lock指令会锁定共享变量所在的所有缓存行,变量更新完成同步回主存后再释放,这样就会产生一个性能问题,当一个线程更新变量时,其他线程都无法对该变量的相邻变量操作了(因为相邻变量被预读取在同一缓存行)。

造成这种情况的根本原因在于,volatile锁定了缓存行,故要想优化volatile,可以使用填充空白字节的方法,将多个无关的共享变量存放在多个缓存行中。但这样做并不都是有利的,因为填充空白字节使得对象膨胀。

 

 

参考:http://ifeve.com/volatile/

  http://ifeve.com/disruptor-cacheline-padding/

jvm-volatile

标签:idt   rup   top   ide   产生   多级   table   png   vol   

原文地址:http://www.cnblogs.com/holoyong/p/7620542.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!