趣谈Java变量的可见性问题
了解过多线程的我们,对synchorized,sleep和valatile都比较了解,但是当这三个名词和“Java变量得可见性”的话题联系在一起不知道大家是否还可以保持大脑清晰???
最近看到一个关于Java变量可见性的问题,感觉比较新鲜就查了一些资料,下面分享给大家:
首先给大家看一段关于多线程的执行代码:
- package com.test;
- import java.util.concurrent.TimeUnit;
- public class test1 {
- private static boolean is = true;
- public static void main(String[] args) {
- new Thread(new Runnable() {
- @Override
- public void run() {
- int i = 0;
- while(test1.is){
- i++;
- 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; //设置is为false,使上面的线程结束while循环
- }
- }).start();
- }
- }
在运行当前代码时,我们会发现程序可以正常运行,但是如果取消注释行(1-3)中的任意一行,程序都会终止,我们不免产生疑问:为什么?synchronized会强制刷新主内存的变量值到线程栈??那么sleep是干嘛的?
下面一起来解决代码执行过程中产生的问题:
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++” 的代码后面加上下面的代码:
- for(int k=0;k<100000;k++){
- new Object();
- }
这时,我们重新运行程序,程序会立刻终止,这又是为什么?
因为我们知道当CPU在被占用的时候,数据的可见性得不到很好的保证。就像上面的例子中,没有添加代码之前,程序会一直循环做i++操作,所以CPU会被运算占用;而对于大量的new Object()操作来说,CPU已经不是主要站时间的操作,真正的耗时应该在内存的分配上(因为CPU的处理速度明显快过内存,不然也不会有CPU的寄存器了),所以CPU空闲后会遵循jvm优化基准,尽可能快的保证数据的可见性,从而从主存将is变量同步到工作内存中,最终导致程序的结束,这也就是sleep()方法虽然没有涉及到同步操作,却依然可以让程序终止的原因,因为sleep()方法会释放CPU,但并不会释放锁;
后记
➷ 知识扩展:
volatile:此关键字保证了变量在线程的可见性,所有线程访问由volatile修饰的变量,都必须从主存中读取后操作,并在工作内存修改后立即写回主存,保证了其他线程的可见性,同样效果的关键字还有final。
synchronized:所有同步操作都必须保证 1、原子性 2、可见性,所以在同步块中发生的变化会立马写回主存
sleep:此方法只会让出CPU执行时间,并不会释放锁;
➷ 寄语
技术在于不断的发现和总结,我们需要将自己输入的知识进行整理后输出,这样才能对输入的知识更好的理解;以上纯属个人理解,如有错误,请大家指正;
趣谈Java变量的可见性问题的更多相关文章
- 关于Java变量的可见性问题
转自:http://www.importnew.com/19434.html 博文前提 最近在oschina问答板块看到了一个关于java变量在工作内存和主存中的可见性问题:synchorized,s ...
- 浅谈Java变量的初始化顺序详解
规则1(无继承情况下):对于静态变量.静态初始化块.变量.初始化块.构造器,它们的初始化顺序依次是(静态变量.静态初始化块)>(变量.初始化块)>构造器证明代码: 复制代码 代码如下: p ...
- Java多线程中变量的可见性
之所以写这篇博客, 是因为在csdn上看到一个帖子问的就是这个问题. 废话不多说, 我们先看看他的代码(为了减少代码量, 我将创建线程并启动的部分修改为使用方法引用). 1 2 3 4 5 6 7 8 ...
- 浅谈Java和JavaScript中变量和数据类型的区别
对于一门编程语言的学习,如果第一步是安装环境,那么第二步一定是学习这门语言的基本规则,变量和数据类型则首当其冲 JavaScipt作为一个蹭Java热度而命名的语言,在很多方面和Java也有一定的相似 ...
- 沉淀再出发:再谈java的多线程机制
沉淀再出发:再谈java的多线程机制 一.前言 自从我们学习了操作系统之后,对于其中的线程和进程就有了非常深刻的理解,但是,我们可能在C,C++语言之中尝试过这些机制,并且做过相应的实验,但是对于ja ...
- 浅谈Java的内存模型以及交互
本文的内存模型只写虚拟机内存模型,物理机的不予描述. Java内存模型 在Java中,虚拟机将运行时区域分成6中,如下图: 程序计数器:用来记录当前线程执行到哪一步操作.在多 ...
- 浅谈Java中的equals和==(转)
浅谈Java中的equals和== 在初学Java时,可能会经常碰到下面的代码: 1 String str1 = new String("hello"); 2 String str ...
- 浅谈Java中的对象和引用
浅谈Java中的对象和对象引用 在Java中,有一组名词经常一起出现,它们就是“对象和对象引用”,很多朋友在初学Java的时候可能经常会混淆这2个概念,觉得它们是一回事,事实上则不然.今天我们就来一起 ...
- 浅谈Java中的equals和==
浅谈Java中的equals和== 在初学Java时,可能会经常碰到下面的代码: String str1 = new String("hello"); String str2 = ...
随机推荐
- Eclipse 的一些调试技巧(转)
原文:http://blog.csdn.net/manymore13/article/details/8972602 1.条件断点 如果你不知道如何添加断点,只需点击左边面板(行号前面)断点即被创建. ...
- 【BZOJ】2289: 【POJ Challenge】圆,圆,圆
题解 二分一个横坐标,过这个横坐标做一条和y轴平行的直线,相当于在这条直线上做区间覆盖,如果区间有交的话,那么答案是True 否则的话取两个不相交的区间,如果这两个圆相离或相切则不合法 否则看看相交的 ...
- Linux环境Tomcat运行报错java.lang.OutOfMemoryError
java.lang.OutOfMemoryError thrown from the UncaughtExceptionHandler in thread "http-bio-8080-ex ...
- 微信小程序之下拉刷新,上拉加载更多
近日开发微信小程序,发现上拉加载更多没有友好的API,而下拉刷新很nice,所以本人按照API,很简单的写了一个示例,希望对大家有帮助,本人用的是iview-webapp 小程序UI框架. 1. 首 ...
- java 生成随机数字
for(int i=0;i<size1;i++){ int n = (int)(java.lang.Math.random()*99); LinkNode newLink = new LinkN ...
- 不同浏览器的userAgent
一.IE浏览器 //IE6 "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)" //IE7 "Mozill ...
- jsonp的理解
众所周知:在开发过程中,有时候需要客户端从服务器接收或向服务器发送一些数据:如果使用普通的ajax,则会遇到跨域访问无权限的问题. 要解决这个问题,就需要了解一下jsonp了: 1. ajax请求普通 ...
- BZOJ.3139.[HNOI2013]比赛(搜索 Hash)
题目链接 不会搜索了.. DFS()中两个参数,枚举每两个队伍的比赛结果(分配当前队伍的分数). 可以发现方案数量与具体哪只球队得了多少分无关,只与当前比赛的队伍数量和得分序列的组成有关.可以记忆化搜 ...
- ios优秀的第三方框架
1.数据请求,object-c AFNetworking 网址:https://github.com/AFNetworking/AFNetworking swift Alamofire 网址:h ...
- 使用WindowsAPICodePack实现翻译功能
仅限于以下几种语言间的翻译: 在我的另一篇博文<图片批量压缩>中,有介绍WindowsAPICodePack库,该库是微软提供的一套基于Win7及以上版本操作系统的系统库,可以帮助我们完成 ...