Java 并发 关键字volatile
Java 并发 关键字volatile
@author ixenos
volatile只是保证了共享变量的可见性,不保证同步操作的原子性
同步块 和 volatile 关键字机制
synchronized
同步块大家都比较熟悉,通过 synchronized 关键字来实现,所有加上synchronized 和 块语句,在多线程访问的时候,同一时刻只能有一个线程能够用synchronized 修饰的方法 或者 代码块。
volatile
用volatile修饰的变量,线程在每次刚使用变量的时候,都会读取变量修改后的最新的值的副本到线程栈中。volatile很容易被误用来进行原子性操作,因为线程对其操作只是副本上,并不会实时更改共享内存中的变量值。
VM为什么要使用副本呢,在副本上操作时可以进行读写操作的重排序优化,能提升运行效率,而是用volatile将禁止副本的使用,而且在volatile变量周围限制重排序操作,具体分析请看:深入理解Java内存模型(四)——volatile
下面看一个例子,我们实现一个计数器,每次线程启动的时候,会调用计数器inc方法,对计数器进行加一
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使线程直接和共享内存的数据交互,并阻止VM的重排序优化
对于volatile修饰的变量,jvm虚拟机只是保证从主内存加载到线程工作内存的值是最新的
Java 并发 关键字volatile的更多相关文章
- Java并发关键字Volatile 详解
Java并发关键字Volatile 详解 问题引出: 1.Volatile是什么? 2.Volatile有哪些特性? 3.Volatile每个特性的底层实现原理是什么? 相关内容补充: 缓存一致性协议 ...
- Java并发—— 关键字volatile解析
简述 关键字volatile可以说是Java虚拟机提供的最轻量级的同步机制,当一个变量定义为volatile,它具有内存可见性以及禁止指令重排序两大特性,为了更好地了解volatile关键字,我们可以 ...
- java多线程关键字volatile的使用
java多线程关键字volatile的作用是表示多个线程对这个变量共享. 如果是只读的就可以直接用,写数据的时候要注意同步问题. 例子: package com.ming.thread.volatil ...
- Java并发编程 Volatile关键字解析
volatile关键字的两层语义 一旦一个共享变量(类的成员变量.类的静态成员变量)被volatile修饰之后,那么就具备了两层语义: 1)保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了 ...
- java并发:volatile关键字
java并发需要保证原子性,可见性,有序性. http://www.cnblogs.com/expiator/p/9226775.html 一.volatile关键字作用如下: 1.volatile关 ...
- Java 并发:volatile 关键字解析
摘要: 在 Java 并发编程中,要想使并发程序能够正确地执行,必须要保证三条原则,即:原子性.可见性和有序性.只要有一条原则没有被保证,就有可能会导致程序运行不正确.volatile关键字 被用来保 ...
- java并发系列(六)-----Java并发:volatile关键字解析
在 Java 并发编程中,要想使并发程序能够正确地执行,必须要保证三条原则,即:原子性.可见性和有序性.只要有一条原则没有被保证,就有可能会导致程序运行不正确.volatile关键字 被用来保证可见性 ...
- Java并发编程volatile关键字
volatile理解 Java语言是支持多线程的,为了解决线程并发的问题,在语言内部引入了 同步块 和volatile 关键字机制.volatile具有synchronized关键字的“可见性”,vo ...
- 一起来看看java并发中volatile关键字的神奇之处
并发编程中的三个概念: 1.原子性 在Java中,对基本数据类型的变量的读取和赋值操作是原子性操作,即这些操作是不可被中断的,要么执行,要么不执行. 2.可见性 对于可见性,Java提供了volati ...
随机推荐
- PDF.NET开发框架性能剖析
PDF.NET开发框架性能剖析 前俩天发布了 关于PDF.NET开发框架对Mysql Sqlite PostgreSQL数据库分页支持的个人看法 ,说明了本人对框架的一些介绍和看法.今天我们一起思考一 ...
- iOS手动管理内存
虽然iOS已经有了ARC帮你自动管理内存,但在有些项目中必须采用手动的方式,而且在懂得手动管理内存的情况下会是自己的代码更加完善 众所周知,基于手动管理内存的情况下必然涉及到 relese reta ...
- struts2 action 接受数组参数为Null的问题
public List<FormulaDetail> formulaDetails; public List<FormulaDetail> getFormulaDetails( ...
- 数模学习笔记(五)——BP神经网络
1.BP神经网络是一种前馈型网络(各神经元接受前一层的输入,并输出给下一层,没有反馈),分为input层,hide层,output层 2.BP神经网络的步骤: 1)创建一个神经网络:newff a.训 ...
- Entity Framework 之 Code First
使用NuGet助您玩转代码生成数据————Entity Framework 之 Code First [前言] 如果是Code First老鸟或者对Entity Framework不感兴趣,就不用浪费 ...
- vsftp FTP服务器外网访问设置
引用: linux中VSFTP无法从外网访问问题! http://blog.csdn.net/zbulrush/article/details/841978 原文: FTP协议有两种工作方式:PORT ...
- 谱聚类(Spectral Clustering)详解
谱聚类(Spectral Clustering)详解 谱聚类(Spectral Clustering, SC)是一种基于图论的聚类方法——将带权无向图划分为两个或两个以上的最优子图,使子图内部尽量相似 ...
- MacOSX高分屏图片打包工具tiffutil的简单使用
You can use the man command tiffutil with the option -cathidpicheck. The command lets you manipulate ...
- 精通CSS+DIV基础总结(三)
Div+CSS可是实现简单的网页设计,对于需要添加动作,更方便的交互,Javascript给我们提供了方便:数据的存储可以利用XML使其更加方便:而对于减少页面与服务器的交互,可以利用Ajax技术,与 ...
- linux下php-5.4.8.tar.gz编译安装全攻略
首先安装基础依赖组建,注:这些依赖组建也是LINUX+PHP+MYSQL+APACHE+NGINX+MEMCACHED时必要的系统组件 LANG=C yum -y install gcc gcc-c ...