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

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

synchronized

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

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

volatile

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

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

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

public class Counter {

public static int count = 0;

public static void inc() {

//这里延迟1毫秒,使得结果明显

try {

Thread.sleep(1);

} catch (InterruptedException e) {

}

count++;

}

public static void main(String[] args) {

//同时启动1000个线程,去进行i++计算,看看实际结果

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

new Thread(new Runnable() {

@Override

public void run() {

Counter.inc();

}

}).start();

}

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

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

}

}

运行结果:Counter.count=995

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

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

public class Counter {

public volatile static int count = 0;

public static void inc() {

//这里延迟1毫秒,使得结果明显

try {

Thread.sleep(1);

} catch (InterruptedException e) {

}

count++;

}

public static void main(String[] args) {

//同时启动1000个线程,去进行i++计算,看看实际结果

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

new Thread(new Runnable() {

@Override

public void run() {

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关键字的含义_Java里volatile关键字是什么意思相关推荐

  1. java中反射机制的含义_java的反射是什么意思?

    反射是Java的特征之一,是一种间接操作目标对象的机制. Java反射机制指的是在Java程序运行状态中,对于任何一个类,都可以获得这个类的所有属性和方法:对于给定的一个对象,都能够调用它的任意一个属 ...

  2. java中事物是什么意思_java里 声明式事务是什么意思呢?

    声明式事务(declarative transaction management)是Spring提供的对程序事务管理的方式之一. Spring的声明式事务顾名思义就是采用声明的方式来处理事务.这里所说 ...

  3. java中实现具有传递性吗_Java中volatile关键字详解,jvm内存模型,原子性、可见性、有序性...

    一.Java内存模型 想要理解volatile为什么能确保可见性,就要先理解Java中的内存模型是什么样的. Java内存模型规定了所有的变量都存储在主内存中.每条线程中还有自己的工作内存,线程的工作 ...

  4. [转载] Java中如何引用另一个类里的集合_Java工程师面试题整理

    参考链接: 在Java中将预定义的类名用作类或变量名 花了一星期把学过的都整理一遍 尽量易懂,从基础到框架 最新版大厂面经汇总出炉,持续更新中 汇总完了上传网盘,设计到后端架构师的一切知识 如果没更新 ...

  5. JAVA中的this怎么理解_Java中的this关键字怎么理解?

    一.this关键字主要有三个应用: (1)this调用本类中的属性,也就是类中的成员变量: (2)this调用本类中的其他方法: (3)this调用本类中的其他构造方法,调用时要放在构造方法的首行. ...

  6. java关键字this含义_java的关键字this的意义及作用

    一.this关键字主要有三个应用: (1)this调用本类中的属性,也就是类中的成员变量: (2)this调用本类中的其他方法: (3)this调用本类中的其他构造方法,调用时要放在构造方法的首行. ...

  7. 在java中使用关键字导入包_java的import关键字的使用

    在java中如何使用Java包中自带的类呢? 方法一: 在使用时可以用Java.(包名).(方法名).(包中的类名): 例如:Java.util.Arrays.toString(某个要排序数组); 具 ...

  8. java中for的常规用法_Java for循环的几种用法详解

    本文非常适合初学Java的程序员,主要是来了解一下Java中的几种for循环用法,分析得十分详细,一起来看看. J2SE 1.5提供了另一种形式的for循环.借助这种形式的for循环,可以用更简单地方 ...

  9. JAVA中的异常的触发_java中的异常

    在日常的程序开发中难免会出现遗漏并且就算代码没有问题可是由于程序运行环境的内存不够了,磁盘满了,网络连接问题等这些非正常的情况在java中都称之为异常.在java中对异常的处理有统一的异常处理机制,今 ...

最新文章

  1. crm创建和编辑全局选项集
  2. hikaripool连接保持_springboot2的hikari数据库连接池默认配置
  3. 合成孔径雷达技术——概述
  4. Spring 极速集成注解 Redis 实践
  5. 【51单片机快速入门指南】3.2:定时器/计数器
  6. 网上的很多Android项目源码有用吗?Android开发注意的地方。
  7. TrackBack 技术规范
  8. 编程中的那些容易迷糊的小知识
  9. zabbix 时间错误_监控的朋友看过来,官方社区专家开源的Zabbix报表系统
  10. sql无效字符 执行sql语句报错解决方案
  11. RocketMQ Client 编码快速入门 与 可视化控制台
  12. 工业嵌入式移动软件设计
  13. 基于TI-RTOS的CC2650DK开发(20)---硬件抽象层
  14. srsLTE 源码分析 UE_09 随机接入 之PRACH发送
  15. html div全屏遮罩层,div遮罩层_Jquery全屏遮罩层DIV的实现代码
  16. SaaS小读-客户成功
  17. VsCode打开终端的方法
  18. CDOJ-1057 秋实大哥与花(线段树区间更新)
  19. 财路网每日原创推送:那些被滥用的区块链关键词
  20. 高质量pdf转换ppt软件绿色版

热门文章

  1. c查看变量类型_Python入门对象与变量
  2. VUe3 @cli(axios)跨域访问
  3. 弱密码校验_TomCat8 弱密码上传getshell
  4. java设计模式之美_《设计模式之美》-笔记
  5. blink usb无线网卡驱动 linux,最新blink随身wifi驱动下载地址电脑版-CC软件
  6. Mongo DB教程及SQL与Mongo DB查询的映射
  7. (二)为AI时尚分类准备数据
  8. 微软进一步融合 Linux,VS Code 官方支持树莓派
  9. 看完就懂webpack打包原理
  10. PostgreSQL 12 正式发布