运行下面的代码:

package com.test.www;public class Test {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() {@Overridepublic void run() {Test.inc();System.out.println(Thread.currentThread().getName());}}).start();}try {Thread.sleep(3000);} catch (Exception e){}//这里每次运行的值都有可能不同,可能为1000System.out.println("运行结果:Counter.count=" + Test.count);}
}

最后运行结果经常会变化,有时候1000,有时候999这样。

count字段添加volidate修饰,保证每次从主线程中取得的数据是最新的。但是结果还是这样?为什么呢?

public class Test {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() {@Overridepublic void run() {Test.inc();System.out.println(Thread.currentThread().getName());}}).start();}try {Thread.sleep(3000);} catch (Exception e){}//这里每次运行的值都有可能不同,可能为1000System.out.println("运行结果:Counter.count=" + Test.count);}
}

在 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关键字修改之后,还是会存在并发的情况。

转载于:https://www.cnblogs.com/snake-hand/archive/2013/06/08/3127493.html

Java学习笔记45:Java 线程与主线程之间的变量关系相关推荐

  1. Java学习笔记:创建线程的两种方法

    Java学习笔记:创建线程的两种方法 一.预备工作 1.创建Maven项目ThreadDemo 2.在pom.xml里添加依赖 二.继承Thread类创建子线程

  2. Java学习笔记1:Java中有关print、println、printf的用法和区别

    Java学习笔记1:Java中有关print.println.printf的用法和区别 最近在学习java,写一些笔记记录下. 1.print()函数是一般的标准输出,但是不换行. 2.println ...

  3. handler回调主线程_Android使用Handler实现子线程与子线程、子线程与主线程之间通信...

    转载:https://blog.csdn.net/shaoenxiao/article/details/54561753 今天这篇文章只讲一下怎么使用Handler实现子线程与子线程之间.子线程与主线 ...

  4. Java学习笔记(java基础)

    Java学习笔记(第一周) Java 介绍 Java 发展方向 JVM , JDK , JRE 名词解释 Java语言的特点 Java安装 安装包的下载 配置环境变量 验证是否安装成功 Java的第一 ...

  5. 【java】java学习笔记之java oop(面向对象)

    如下图所示为笔者总结的java oop(面向对象)学习笔记,其中,附带有代码示例(未展开),方便理解记忆.需要源文件的请到我的资源中下载,下载地址:https://download.csdn.net/ ...

  6. 【java】java学习笔记之java常用类

    如下图所示为笔者总结的java常用类学习笔记,其中,附带有代码示例(未展开),方便理解记忆.需要源文件的请到我的资源中下载,下载地址:https://download.csdn.net/downloa ...

  7. Java 学习笔记(4)——java 常见类

    上次提前说了java中的面向对象,主要是为了使用这些常见类做打算,毕竟Java中一切都是对象,要使用一些系统提供的功能必须得通过类对象调用方法.其实Java相比于C来说强大的另一个原因是Java中提供 ...

  8. Java学习笔记01—Java概述、数据类型、变量、标识符、类型转换

    1. Java概述 1.1 Java语言发展史(了解) 语言:人与人交流沟通的表达方式 计算机语言:人与计算机之间进行信息交流沟通的一种特殊语言 Java语言是美国Sun公司(Stanford Uni ...

  9. java学习笔记(一) ----java下常用的包功能

    ***java下常用的包*** java.lang----包含一些java语言的核心类,如String,Math,Integer,System,Thread,提供常用的功能. java.awt---- ...

最新文章

  1. linux 下 jenkins 安装注意事项
  2. MATLAB 图像的平滑和边缘检测
  3. 用户不见了_屋面瓦/外墙板再也看不见螺丝打胶了
  4. 交叉验证(Cross Validation)方法思想简介
  5. 干货分享:什么是Java设计工厂模式?
  6. android.os.build修改,Android的os.BuildID对应的SDK版本号以及SDK版本号与APILevel对应关系.docx...
  7. JavaMVC之JSON
  8. 数值计算(Python实现)(一)
  9. ajax css文件,wordpress 添加JS,css文件,实现AJAX效果
  10. 问题二十三:C++中debug简单的运行死机问题
  11. php获取udid,iOS获取设备真实UDID和IMEI
  12. 显示计算机101代码,电脑出现蓝屏故障101停机码,怎么解决问题
  13. 德乐生 java_【Senior Java Developer怎么样】德乐生软件2021年Senior Java Developer前景怎么样-看准网...
  14. hdu-1022-Train Problem I
  15. 二叉树遍历的非递归实现
  16. 数据分析---数据处理工具pandas(二)
  17. 词云中去重复的词_李清照特别经典的词,把相思写得淋漓尽致,读一次心疼一次...
  18. 生物信息中的Markov链
  19. 【蓝月传奇3D】手游辅助脚本(多开/练级/日常/BOSS/活动等)
  20. android 横竖屏坐标转换,Android:横竖屏转换问题

热门文章

  1. 大数据学习01——配置虚拟机节点相关网络
  2. php rabbmq教程_RabbitMQ+PHP 教程一(Hello World)
  3. 2022-2028年中国pu管行业市场深度分析及市场规模预测报告
  4. 浅显易懂 Makefile 入门 (02)— 普通变量和自动变量定义、使用($@、$^、$< 作用)、变量覆盖 override、变量的来源 origin
  5. 机房收费系统总结【1】-整体流程
  6. 数据类型对应的字节数
  7. ADAS摄像头20个技术挑战
  8. GPU与CPU交互技术
  9. 芯片IP,SOC,FPGA智能卡
  10. CodeGen融合核心关系循环扩展