趣谈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 = ...
随机推荐
- Java编程的逻辑 (56) - 文件概述
本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http:/ ...
- .NetCore WebApi利用Swagger文档实现选择文件上传
介绍 实现这个功能主要还是依赖过滤器 在Swagger中利用 IOperationFilter 操作来实现文件上传 与之前处理结合Idr4授权一样的处理方式,不同的是授权处理的是Security,而文 ...
- Django为数据库的ORM写测试例(TestCase)
models.py里的数据库定义如下: from django.db import models # Create your models here. class Teachers(models.Mo ...
- 二维码生成delphi版
二维码生成delphi版 生成二维码的软件,代码从C语言转换过来(源地址:http://fukuchi.org/works/qrencode/),断断续续的差不多花了一周时间来转换和调试.在转换过程中 ...
- SpringMVC框架07——服务器端JSR303数据校验
1.数据校验概述 数据校验分为客户端校验和服务器端校验,客户端主要是通过过滤正常用户的误操作,是第一道防线,一般使用JavaScript代码实现.但是只有客户端校验是不够的,攻击者可以绕过客户端验证直 ...
- BZOJ2190 [SDOI2008]仪仗队 [欧拉函数]
题目描述 作为体育委员,C君负责这次运动会仪仗队的训练.仪仗队是由学生组成的N * N的方阵,为了保证队伍在行进中整齐划一,C君会跟在仪仗队的左后方,根据其视线所及的学生人数来判断队伍是否整齐(如下图 ...
- NOIP练习赛题目4
肥得更高 难度级别:C: 运行时间限制:1000ms: 运行空间限制:51200KB: 代码长度限制:2000000B 试题描述 自2009年以来,A.B站的历史就已经步入了农业变革的黎明期.在两站的 ...
- java集合之Link的比较
概要 前面,我们学完了List的全部内容(ArrayList, LinkedList, Vector, Stack). 现在,我们再回头看看总结一下List.内容包括:第1部分 List概括第2部分 ...
- bzoj 2809 可并堆维护子树信息
对于每个节点,要在其子树中选尽量多的节点,并且节点的权值和小于一个定值. 建立大根堆,每个节点从儿子节点合并,并弹出最大值直到和满足要求. /***************************** ...
- TreeMap(红黑树)源码分析
1. HashMap.Entry(红黑树节点) private static final boolean RED = false; private static final boolean BLACK ...