关于Java变量的可见性问题
转自:http://www.importnew.com/19434.html
博文前提
最近在oschina问答板块看到了一个关于java变量在工作内存和主存中的可见性问题:synchorized,sleep 也能达到volatile 线程可见性的目的?,大致的问题描述如下:
package com.test; import java.util.concurrent.TimeUnit; public class Test01 { private static boolean is = true; public static void main(String[] args) { new Thread(new Runnable() { @Override
public void run() {
int i = 0;
while (Test01.is) { i++; // byte[] bts = new byte[1024*1024*2];
// byte[] bts1 = new byte[1024*1024*1];
// byte[] bts2 = new byte[1024*1024*3]; // 1. synchronized (this) { } 会强制刷新主内存的变量值到线程栈?
// 2. System.out.println("1"); println 是synchronized 的,会强制刷新主内存的变量值到线程栈?
// 3. sleep 会从新load主内存的值?
// try {
// TimeUnit.MICROSECONDS.sleep(1);
// }catch (InterruptedException e) {
// e.printStackTrace();
// } }
}
}).start(); try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
} new Thread(new Runnable() { @Override
public void run() {
// 设置is为false,使上面的线程结束while循环
Test01.is = false;
} }).start();
} }
问:
为什么整个程序不会终止?
为什么取消注释中的任何一个代码块(1,2,3),程序才会终止?
synchronized 会强制刷新住内存的变量值到线程栈?
sleep 会干什么呢?
涉及知识解释
- volatile:此关键字保证了变量在线程的可见性,所有线程访问由volatile修饰的变量,都必须从主存中读取后操作,并在工作内存修改后立即写回主存,保证了其他线程的可见性,同样效果的关键字还有final。
- synchronized:所有同步操作都必须保证 1、原子性 2、可见性,所以在同步块中发生的变化会立马写回主存
- sleep:此方法只会让出CPU执行时间,并不会释放锁。
问题分析
Q1:为什么注释代码后程序不会终止?
A1:因为 boolean is=true 的变量值被前面线程(简称线程A)加载到自己的工作内存,在后面的线程(简称线程B)改变 boolean is=false 之后不一定会立马写入主存(不过这道题中应该会马上写入主存,因为线程执行完 is=false之后线程就要退出了),即便立马写入了主存后线程A也不一定马上load到工作内存中,所以程序一直不会终止?这个是我们大多数人想到的,但其实JVM针对现在的硬件水平已经做了很大程度的优化,基本上很大程度的保障了工作内存和主内存的及时同步,相当于默认使用了volatile。但只是最大程度!在CPU资源一直被占用的时候,工作内存与主内存中间的同步,也就是变量的可见性就会不那么及时!后面会验证结论。
Q2:为什么取消注释中的任何一个代码块(1,2,3),程序才会终止?
A2:行号为1、2的代码有一个共同特点,就是都涉及到了synchronized 同步锁,那么是否像提问作者猜想的那样synchronized会强制刷新主内存的变量值到线程栈?
,以及sleep方法也会刷新主存的变量值到线程栈呢?
,事实上我们前面说了synchronized只会保证在同步块
中的变量的可见性,而is
变量并不在该同步块中,所以显然不是这个导致的。
接下来我们在代码i++;
后面加上以下代码:
byte[] bts = new byte[1024*1024*2];
byte[] bts1 = new byte[1024*1024*1];
byte[] bts2 = new byte[1024*1024*3];
再Run,程序立刻终止!为什么?
在上面的 A1 中我们已经说了即便有JVM的优化,但当CPU一直被占用的时候,数据的可见性得不到很好的保证,就像上面的程序一直循环做i++;运算
占用CPU,而为什么加上上面的代码后程序就会停止呢?因为对于几个new byte[1024*1024*1]操作来说,CPU已经不是主要占时间的操作,真正的耗时应该在内存的分配上(因为CPU的处理速度明显快过内存,不然也不会有CPU的寄存器了)
,所以CPU空闲后会遵循JVM优化基准,尽可能快的保证数据的可见性,从而从主存同步is变量到工作内存,最终导致程序结束,这也是为什么sleep()
方法虽然没有涉及同步操作,但是依然可以使程序终止,因为sleep()
方法会释放CPU,但不释放锁!
关于Java变量的可见性问题的更多相关文章
- 趣谈Java变量的可见性问题
了解过多线程的我们,对synchorized,sleep和valatile都比较了解,但是当这三个名词和“Java变量得可见性”的话题联系在一起不知道大家是否还可以保持大脑清晰??? 最近看到一个关于 ...
- Java多线程中变量的可见性
之所以写这篇博客, 是因为在csdn上看到一个帖子问的就是这个问题. 废话不多说, 我们先看看他的代码(为了减少代码量, 我将创建线程并启动的部分修改为使用方法引用). 1 2 3 4 5 6 7 8 ...
- java并发之可见性与原子性:Syncronized和volatile
转载:http://blog.csdn.net/guyuealian/article/details/52525724 在说明Java多线程内存可见性之前,先来简单了解一下Java内存模型. ...
- java并发编程可见性与线程封闭
可见性 所谓可见性,指的是当一个线程修改了对象的状态后,其他线程能够看到该对象发生的变化.在单线程环境下,向某个变量写入值,然后在后面的操作再读取,在这个过程中该变量的值对该线程来说总是可见.但是,在 ...
- Java-JUC(二):Java内存模型可见性、原子性、有序性及volatile具有特性
1.Java HotSpot JVM运行时数据区 Java内存模型即Java Memory Model,简称JMM.JMM定义了Java 虚拟机(JVM)在计算机内存(RAM)中的工作方式.JVM是整 ...
- Java-Runoob:Java 变量类型
ylbtech-Java-Runoob:Java 变量类型 1.返回顶部 1. Java 变量类型 在Java语言中,所有的变量在使用前必须声明.声明变量的基本格式如下: type identifie ...
- (七)Java 变量类型
Java 变量类型 在Java语言中,所有的变量在使用前必须声明.声明变量的基本格式如下: type identifier [ = value][, identifier [= value] ...] ...
- Java——变量类型
Java变量类型: 在Java中,所有的变量在使用前必须声明.格式: type identifier [ = value ][, identifier [ =value]-.]; type为Java数 ...
- 菜鸟笔记:java变量命名及峰驼式命名法
如同酒店会给每个房间起个性化的名字一样,程序中的变量也需要用合理的名字进行管理---变量名! 需要注意,给酒店房间起名字时可以是数字,如"802",也可以是有趣的名字,如" ...
随机推荐
- cf220b
不知道为什么线段树区间更新专题里有这题.. 可以用莫队解,也可以直接开数组解 /* n个询问,m个元素 O(m*m):记录每个元素出现次数,筛掉出现次数小于数值的数 */ #include<io ...
- windows 系统常用操作
1.所有端口使用情况 netstat -ano 2.查询xxxx端口pid netstat -aon|findstr "xxxx" 3.根据端口Pid查详情 tasklist|fi ...
- 20155309南皓芯 网络对抗《网络攻防》 Exp1 PC平台逆向破解(5)M
实践目标 本次实践的对象是linux的可执行文件 该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串. 该程序同时包含另一个代码片段,getShell,会返回一个可 ...
- ireport 添加行自增序号
ireport 添加行自增序号 在ireport报表中加入行的自增序号方法: 添加一个变量,如变量名为 index: 设置变量类型为Integer,计算类型为count:变量表达式为$V{index} ...
- 【Algorithm | 链表】单链表“环”、“环的起点”、“环的长度”问题
参考资料 • Floyd判圈算法 { 链接 } • 单链表“环”.“环的起点”.环的长度”问题 { 链接 } 链表环的问题 一.判断链表有换 使用两个指针slow和fast.两个指针开始时均在头节点处 ...
- hdu 1005 根据递推公式构造矩阵 ( 矩阵快速幂)
f(1) = 1, f(2) = 1, f(n) = (A * f(n - 1) + B * f(n - 2)) mod 7. Sample Input1 1 3 //a b n1 2 100 0 0 ...
- A. 【UR #17】滑稽树上滑稽果
题解: 首先很显然的是这是一条链(特殊数据说是链是故意让人迷茫的??) 然后 自己就开始yy 觉得每一次是加入一个使得当前值最小的数 然而这tm又是特殊数据?? 那就写一波发现是错的 考虑一下特殊数据 ...
- BZOJ1588 [HNOI2002]营业额统计 set
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1588 题意概括 给出数列,求 ∑F[i],其中F[1] = a[1] , F[i] = min( ...
- BZOJ1296 [SCOI2009]粉刷匠 动态规划 分组背包
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1296 题意概括 有 N 条木板需要被粉刷. 每条木板被分为 M 个格子. 每个格子要被刷成红色或蓝 ...
- 最长上升序列 LCS LIS
子序列问题 (一)一个序列中的最长上升子序列(LISLIS) n2做法 直接dp即可: ;i<=n;i++) { dp[i]=;//初始化 ;j<i;j++)//枚举i之前的每一个j ) ...