volatile在java server模式和client模式下的不同(主内存和工作内存)

来源:互联网 发布:jdk1.8 for linux下载 编辑:程序博客网 时间:2024/06/06 21:39

因为要做一个java多线程的培训,而自己对多线程的理解也是一知半解。

尤其困惑的地方是对volatile关键字的理解。

好了,现在步入正题。

volalte的关键字是在多线程共享数据时,共享数据不会备份到各线程的工作内存中,而是直接从主内存中获取最新值,即是线程可见性。

以下是对volatile关键字的测试代码

public class VolatileTest {

 public  volatile   static boolean asleep = true;

 public static void main(String[] args) throws InterruptedException {
  new Thread(new Runnable() {                 //称为线程1吧
   
   @Override
   public void run() {
    while(asleep){
         }
   }
  }).start();
  
  Thread.sleep(1*1000);
  asleep=false;

 }

}

运行结果:

①有volatile关键字时,当主线程把asleep改成false时,线程1停止运行,符合预期结果

②将volatile去掉时,运行结果依然同上。

我纳闷了,为什么。如果是这样的情况,volatile关键字完全没有作用。

后来同事提醒我,将运行参数改成服务器模式,即 -server模式 (我的eclipse里默认执行是client模式)

重复上面步骤

①有volatile关键字时,当主线程把asleep改成false时,线程1停止运行,符合预期结果

②将volatile关键字去掉时,程序陷入死循环,线程1感受不到asleep的变化,埋头苦干。

在网上查资料,以下

JIT或HotSpot编译器在server模式和client模式编译不同,server模式为了使线程运行更快,如果其中一个线程更改了变量boolean flag 的值,那么另外一个线程会看不到,因为另外一个线程为了使得运行更快所以从寄存器或者本地cache中取值,而不是从内存中取值,那么使用volatile后,就告诉不论是什么线程,被volatile修饰的变量都要从内存中取值。《内存栅栏》

说明server对java代码做了更多的优化,而client却没有。

 

笔者不甘心,继续做实验

在-server模式下,修改以上的代码,

 

public class VolatileTest {

 public  volatile   static boolean asleep = true;

 public static void main(String[] args) throws InterruptedException {
  new Thread(new Runnable() {                 //称为线程1吧
   
   @Override
   public void run() {
    while(asleep){

System.out.println("我不信啦!!");
         }
   }
  }).start();
  
  Thread.sleep(1*1000);
  asleep=false;

 }

}

执行代码,这次笔者笑啦

①有volatile关键字时,当主线程把asleep改成false时,线程1停止运行,符合预期结果

②将volatile关键字去掉时,结果如上。

这是为什么呢???

为什么这次不加volatile,线程1又能感受asleep的变化呢????

问题就出在System.out.println("我不信啦!!");这段代码上

因为System.out.println中含有同步块,一执行该方法,变量将从主存中重新读取。

System.out.println如下:

    public void println(String x) {
 synchronized (this) {
     print(x);
     newLine();
 }
    }

为了验证这个验证,笔者继续做实验

在-server模式下,修改以上的代码,

public class VolatileTest {

 public static boolean asleep = true;

 public static void main(String[] args) throws InterruptedException {
  new Thread(new Runnable() {
   public void run() {

    while (asleep) {

//笔者把System.out.printlnd换成了下面
     int a = 1, b = 2;
     int c = a + b;
    }
   }
  }).start();

  Thread.sleep(1 * 1000);
  asleep = false;

 }

}

执行代码,得出如下

①有volatile关键字时,当主线程把asleep改成false时,线程1停止运行,符合预期结果

②将volatile关键字去掉时,程序陷入死循环,线程1感受不到asleep的变化,埋头苦干。

验证我的猜测!!!

结论:

⑴java 在client模式下,多线程读取变量时,都会直接从主内存中去读取,不会保存在工作内存中,所有加不加volatile效果一下,而server模式下,则对代码做了优化。

⑵当在线程中存在同步快时,会强制去主内存重新获取主内存的值。

以上结果全部运行在jdk1.6的环境下

下班啦!!!~~~第一次发博客,心情这个忐忑啊!!

内容有些凌乱,回去在整理 O(∩_∩)O哈哈~

1 0
原创粉丝点击