(支持原创)本篇文章非原创,原文章地址:

http://www.cnblogs.com/aigongsi/archive/2012/04/01/2429166.html

在java线程并发处理中,有一个关键字volatile的使用目前存在很大的混淆,以为使用这个关键字,在进行多线程并发处理的时候就可以万事大吉。

Java语言是支持多线程的,为了解决线程并发的问题,在语言内部引入了 同步块 和 volatile 关键字机制。

synchronized

同步块大家都比较熟悉,通过 synchronized 关键字来实现,所有加上synchronized 和 块语句,在多线程访问的时候,同一时刻只能有一个线程能够用

synchronized 修饰的方法 或者 代码块。

volatile

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

下面看一个例子,我们实现一个计数器,每次线程启动的时候,会调用计数器inc方法,对计数器进行加一

执行环境——jdk版本:jdk1.6.0_31 ,内存 :3G   cpu:x86 2.4G

public classCounter {public static int count = 0;public static voidinc() {//这里延迟1毫秒,使得结果明显

try{

Thread.sleep(1);

}catch(InterruptedException e) {

}

count++;

}public static voidmain(String[] args) {//同时启动1000个线程,去进行i++计算,看看实际结果

for (int i = 0; i < 1000; i++) {new Thread(newRunnable() {

@Overridepublic voidrun() {

Counter.inc();

}

}).start();

}//这里每次运行的值都有可能不同,可能为1000

System.out.println("运行结果:Counter.count=" +Counter.count);

}

}运行结果:Counter.count=995

实际运算结果每次可能都不一样,本机的结果为:运行结果:Counter.count=995,可以看出,在多线程的环境下,Counter.count并没有期望结果是1000

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

public classCounter {public volatile static int count = 0;public static voidinc() {//这里延迟1毫秒,使得结果明显

try{

Thread.sleep(1);

}catch(InterruptedException e) {

}

count++;

}public static voidmain(String[] args) {//同时启动1000个线程,去进行i++计算,看看实际结果

for (int i = 0; i < 1000; i++) {new Thread(newRunnable() {

@Overridepublic voidrun() {

Counter.inc();

}

}).start();

}//这里每次运行的值都有可能不同,可能为1000

System.out.println("运行结果:Counter.count=" +Counter.count);

}

}

运行结果:Counter.count=992

运行结果还是没有我们期望的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的含义_java中volatile关键字的含义相关推荐

  1. java中volatile关键字的含义_java中volatile关键字的含义

    转自:http://www.cnblogs.com/aigongsi/archive/2012/04/01/2429166.html 在java线程并发处理中,有一个关键字volatile的使用目前存 ...

  2. java中volatile关键字的含义_Java里volatile关键字是什么意思

    在java线程并发处理中,有一个关键字volatile的使用目前存在很大的混淆,以为使用这个关键字,在进行多线程并发处理的时候就可以万事大吉. Java语言是支持多线程的,为了解决线程并发的问题,在语 ...

  3. java volatile 基本类型_Java中Volatile关键字详解(转)

    一.基本概念 先补充一下概念:Java 内存模型中的可见性.原子性和有序性. 可见性: 可见性是一种复杂的属性,因为可见性中的错误总是会违背我们的直觉.通常,我们无法确保执行读操作的线程能适时地看到其 ...

  4. java i 线程不安全_java中的++i是线程安全的吗?

    java中的++i是线程安全的吗?为什么?怎么使它线程安全呢? 先说答案: 非线程安全 先说下为什么是非线程安全的? 从Java内存模型说起 Java内存模型规定了所有的便利都存储在主内存中,每个线程 ...

  5. java对于数组的定义_Java中方法的定义与使用,以及对数组的初步了解。

    方法 方法的含义 定义: 方法就是用来完成解决某件事情或实现某个功能的办法. 方法实现的过程中,会包含很多条语句用于完成某些有意义的功能--通常是处理文本,控制输入或计算数值. 我们可以通过在程序代码 ...

  6. java类怎么删除对象_java中对象的生成使用和删除

    请教大神,在java里,对象生成后,如何删除对象呢?请教大神,在java里,对象生成后,如何删除对象呢? 对象状态由JVM自动管理,GC线程自动回收无用对象,无需也不能自己删除对象. 请问在JAVA中 ...

  7. java的布局管理器_Java中提供了几种布局管理器

    近日,很多网友都在关注Java中提供了几种布局管理器这个话题,那么Java中提供了几种布局管理器具体情况是怎么样的呢?Java中提供了几种布局管理器的相关信息有哪些?下面的内容是小编为大家找到的关于J ...

  8. java中组件与容器_java中的容器组件和非容器组件

    1.java使用到的图形类主要在java.awt 与javax.swing包中. 2.java.awt 与 javax.swing包的区别: ① java.awt中使用的图形类都是依赖于系统的图形库的 ...

  9. java boolean几个字节_Java中boolean类型到底占用多少个字节?

    1.时间:2017-07-03 07:37:06YuanMxy 2.问题描述:今天在复习java基础的时候发现一小问题,Java中boolean类型到底占用多少个字节? 3.问题解答: (1)什么是b ...

最新文章

  1. winform groupbox控件放到窗体中间位置
  2. 大地发生了变化写具体_小学语文三年级下册期末检测卷 (2)
  3. layui的登录ajax,layui如何实现登录功能
  4. 如何优雅的升级内核?
  5. 【华为云动态】华为云携手Google,IBM,SAP等多家知名企业加入CDF,助力软件开发生态发展
  6. 树莓派该文件名_树莓派的20个常用命令
  7. 指针和引用的相同与不同
  8. 学习小实例--滚动条
  9. 五、实现一个10秒钟的倒计时,即:从10~0依次打印,每次打印间隔一秒
  10. 雷达的L、S、C、X波段是什么
  11. build lavas 失败_基础教程 - 快速开始 PWA 工程 - 《Lavas 指导教程文档》 - 书栈网 · BookStack...
  12. matlab数值计算习题解析,第3章MATLAB数值计算-习题
  13. 迅捷fw325r虚拟服务器设置,Fast迅捷FW325R无线路由器设置
  14. 图像处理:语义分割(sematic segmentation)
  15. 7、机器视觉之色彩空间转换
  16. 20145325张梓靖 《网络对抗技术》 Web安全基础实践
  17. EasyExcel实现Excel文件导入导出功能
  18. MDT 2013 从入门到精通之Office 2013应答文件生成
  19. centos7下安装mycat2
  20. 使用接口实现翻译日语

热门文章

  1. linux 软硬文件类型,linux文件属性和类型、系统链接文件、软链接和硬链接
  2. 为什么开了数据不能上网_Doinb和LCK选手双排为什么不能开语音?Doinb深夜道出实情...
  3. VTK修炼之道66:体绘制裁剪_Cripping技术
  4. VTK修炼之道5_Procedural Source Object
  5. 深入理解文档/视图框架体系_九宫格项目开发感悟
  6. [计算机视觉:算法与应用]学习笔记一:图像形成
  7. Delphi中的Type
  8. win10电脑如何安装Openssh?开启Server服务?
  9. 程序员面试系列——冒泡排序
  10. spring security认证的底层实现