码迷,mamicode.com
首页 > 编程语言 > 详细

关于java的volatile关键字与线程栈的内容

时间:2015-11-17 20:38:45      阅读:195      评论:0      收藏:0      [点我收藏+]

标签:

  用volatile修饰的变量,线程在每次使用变量的时候,都会读取变量修改后的最新的值。volatile很容易被误用,用来进行原子性操作。

package com.guangshan.test;

public class TestVolatile {
    
    public static int count = 0;
    
    public static void inc () {
        try {
            Thread.sleep(1);
        } catch (Exception e) {

        }
        count++;
    }
    
    public static void main(String[] args) throws InterruptedException {
        
        for (int i = 0; i < 1000; i++) {
            new Thread(new Runnable() {
                
                public void run() {
                    TestVolatile.inc();
                }
            }).start();
        }
        System.out.println(count);
        
        Thread.sleep(1000);
        
        System.out.println(count);
        
    }
}

  这段代码,最后的count值很有可能不为1000(main函数所在的线程为主线程,主线程的最后一句代码执行后,会进入Thread.exit()方法,该方法会强制终止所有该线程创建的线程),在sleep(1000)后,其他加的线程已经结束了,按理讲,这里的count应该为1000的,但是为什么不是1000呢?

  很多人以为,这个是多线程并发问题,只需要在变量count之前加上volatile就可以避免这个问题,那我们在修改代码看看,看看结果是不是符合我们的期望。

  加入volatile之后,仍然有可能不是1000,下面我们分析一下原因

  在 java 垃圾回收整理一文中,描述了jvm运行时刻内存的分配。其中有一个内存区域是jvm虚拟机栈,每一个线程运行时都有一个线程栈,线程栈保存了线程运行时候变量值信息。当线程访问某一个对象时候值的时候,首先通过对象的引用找到对应在堆内存的变量的值,然后把堆内存变量的具体值load到线程本地内存中,建立一个变量副本,之后线程就不再和对象在堆内存变量值有任何关系,而是直接修改副本变量的值,在修改完之后的某一个时刻(线程退出之前),自动把线程变量副本的值回写到对象在堆中变量。这样在堆中的对象的值就产生变化了。下面一幅图描述这写交互

  技术分享

  

  read and load 从主存复制变量到当前工作内存
  use and assign  执行代码,改变共享变量值 
  store and write 用工作内存数据刷新主存相关内容

  其中use and assign 可以多次出现

  但是这一些操作并不是原子性,也就是 在read load之后,如果主内存count变量发生修改之后,线程工作内存中的值由于已经加载,不会产生对应的变化,所以计算出来的结果会和预期不一样

  对于volatile修饰的变量,jvm虚拟机只是保证从主内存加载到线程工作内存的值是最新的

  例如假如线程1,线程2 在进行read,load 操作中,发现主内存中count的值都是5,那么都会加载这个最新的值

  在线程1堆count进行修改之后,会write到主内存中,主内存中的count变量就会变为6

  线程2由于已经进行read,load操作,在进行运算之后,也会更新主内存count的变量值为6

  导致两个线程即使用volatile关键字修改之后,还是会存在并发的情况。

关于java的volatile关键字与线程栈的内容

标签:

原文地址:http://www.cnblogs.com/guangshan/p/4972758.html

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