同步包括两方面的含义: 独占性和可见性。

很多人仅仅理解了独占性,而忽略了可见性。

根据Java Language Specification中的说明, jvm系统中存在一个主内存(Main Memory或Java Heap Memory),Java中所有变量都储存在主存中,对于所有线程都是共享的。

每条线程都有自己的工作内存(Working Memory),工作内存中保存的是主存中某些变量的拷贝,线程对所有变量的操作都是在工作内存中进行,线程之间无法相互直接访问,变量传递均需要通过主存完成。

一种常见的错误是,只有在写入共享变量时才需要同步,而读取的时候并不需要同步。

publicclass GetAndSet {

privateint i;

publicint getI() {

returni;

}

publicsynchronized void setI(int i) {

this.i = i;

}

}

在多线程环境中,仅从独占性上分析,上述程序根本不存在任何问题。

问题出在了可见性上,

即,如果调用

在线程A中:setI(10);

然后在线程B中:getI();

得到的很可能并非10,这个我们想要的答案。

这是因为并没有什么保证,在线程A设置的I,在线程B中可以立马看到当前值。

Java内存模型就是为了解决可见性的问题。

JMM规定了JVM必须遵循的一组最小保证,这组保证规定了对变量的写入操作在何时将对于其他线程是可见的。

这组保证就是Happen-Before 规则。

happen before规则: 
Each action in a thread happens before everyaction in that thread that comes later in the program's order. 
An unlock on a monitor happens before everysubsequent lock on that same monitor. 
A write to a volatile field happens before everysubsequent read of that same volatile. 
A call to start() on a thread happens before anyactions in the started thread. 
All actions in a thread happen before any otherthread successfully returns from a join() on that thread.

happen before翻译过来就是: 
程序顺序规则:一个线程中的每个操作,happens- before 于该线程中的任意后续操作。 
监视器锁规则:对一个监视器锁的解锁,happens- before 于随后对这个监视器锁的加锁。 
volatile变量规则:对一个volatile域的写,happens- before 于任意后续对这个volatile域的读。 
传递性:如果Ahappens- before B,且B happens- before C,那么A happens- before C。 
Thread.start()的调用会happens-before于启动线程里面的动作。 
Thread中的所有动作都happens-before于其他线程从Thread.join中成功返回。

Happen-Before 规则是由JVM提供的,因此无论有没有“同步协助(synchronized,lock ,volatile,final)”,程序执行时都必须遵守这些规则, 只不过这些规则中的大部分和同步协助有关系。

注意:第一条程序顺序规则,按字面意思的话,在同一个线程中所有语句的执行过程,必须按照程序流的先后去执行。不可能有任何重排序的可能。

实际情况并非如此,在同一个线程中,只有有数据相关的操作才不会被重排序,而没有任何关系的操作是可以被编译器发现,并进行适当重排的。

如:inti =10; --------------a

intj =1;----------------------b

i =i+1;----------------------c

虽然 a  hanppen  before b, 可在真实执行的时候,b有可能会在a前执行。因为该线程根本无法感知这种顺序的变化。

可是,a 不可能在c后面执行,因为这个线程本身可以感知这个顺序的变化。

jvm的可见性的理解的更多相关文章

  1. 对JDK、JRE和JVM的一些浅薄理解

    JDK:JDK(Java Development Kit),顾名思义是java程序的开发包,任何java程序想要运行都需要相应版本的JDK,可以到oracle下载(下载之后自带JRE和编译工具等,无需 ...

  2. jvm内存模型的理解

    今天周六,又开始啃一遍<深入理解java虚拟机>每次读的感觉不一样,大学代码量较少,读起来也就死记硬背. 1.堆:长度可变,运行时使用的变量:存放对象(new )和数组之类: 2.栈:长度 ...

  3. 走进JVM【二】理解JVM内存区域

    引言 对于C++程序员,内存分配与回收的处理一直是令人头疼的问题.Java由于自身的自动内存管理机制,使得管理内存变得非常轻松,不容易出现内存泄漏,溢出的问题. 不容易不代表不会出现问题,一旦内存泄漏 ...

  4. Java程序员想年后跳槽,对JVM没有深入的理解,我劝你还是别跳了

    前言 Java 虚拟机是学习 Java 的基础,也是迈入高级 Java 开发工程师的必备知识点.所以今天这篇文章我们来聊聊如何从零开始学习 Java 虚拟机. 深入浅出Java虚拟机 对于刚刚接触 J ...

  5. MVCC - Read View的可见性判断理解

    读了 @SnailMann大佬[MySQL笔记]正确的理解MySQL的MVCC及实现原理 收益颇丰,非常感谢! 但对其中如何判断事务是否可见性还是不太理解,于是作了本文,在原博客基础上,举例画图论证. ...

  6. Java的一些常见问题,JRE,JDK,JVM,包等概念理解

    Java常见错误: 文件名字应该与文件中public类的名字相同 public static void main(String[] args); 如何定位错误和解决错误. JVM,JRE,JDK解释和 ...

  7. JDK,JRE,JVM区别与联系-理解与概括

    我们利用JDK(调用JAVA API)开发了属于我们自己的JAVA程序后,通过JDK中的编译程序(javac)将我们的文本java文件编译成JAVA字节码,在JRE上运行这些JAVA字节码,JVM解析 ...

  8. Java多线程学习笔记——从Java JVM对多线程数据同步的一些理解

       我们知道在多线程编程中,我们很大的一部分内容是为了解决线程间的资源同步问题和线程间共同协作解决问题.线程间的同步,通俗我们理解为僧多粥少,在粥有限情况下,我们怎么去防止大家有秩序的喝到粥,不至于 ...

  9. java线程基础巩固---多线程与JVM内存结构的关系及Thread构造函数StackSize的理解

    继续学习一下Thread的构造函数,在上次[http://www.cnblogs.com/webor2006/p/7760422.html]已经对如下构造都已经学习过了: 多线程与JVM内存结构的关系 ...

随机推荐

  1. python从初识到精通1

    Python3 基本数据类型 Python 中的变量不需要声明.每个变量在使用前都必须赋值,变量赋值以后该变量才会被创建. 在 Python 中,变量就是变量,它没有类型,我们所说的"类型& ...

  2. PHP学习过程_Symfony_(4)_命令创建实体_以及实体关系

    //项目运行php app/console server:run//创建实体php app/console doctrine:generate:entitybundle名称:实体名称例如:Symfon ...

  3. iOS UIImageView自适应图片大小

    窗口大小获取: CGRect screenBounds = [ [UIScreenmainScreen]bounds];//返回的是带有状态栏的Rect CGRect rect = [ [UIScre ...

  4. 关于Android平台的搭建的心得---汪永骏

    我本来是.net开发的,但看到目前互联网形式都朝着移动端开发迈进.大势所向,我便也开始学习Android的开发 今天就是要聊一下,我对Android开发的一些心得.今天讲的是,我在搭建Android平 ...

  5. 5.Struts2的OGNL表达式

    1.创建javaweb项目Struts2_Part4_OGNL并在WebRoot下的WEB-INF下的lib文件夹下添加如下jar文件 commons.jar commons.jar freemark ...

  6. chrome console 命令简记

    1.快速迭代元素 $$('tr.dispute-num td strong a').map(function (el) { return el.innerHTML; }) 2.复选框选中/取消选中 c ...

  7. 设计模式-GoF23

    书呢,是2012年双11买的. 没有面向对象程序经验的人,果然还是看不懂的.

  8. crontab记录

    简单说一下分类: 1.系统定时路径在/etc/crontab,直接进行编辑即可,这里注意,设定执行时间之后,第二个要跟用户名 ,例如: 1 * * * * root run-parts /etc/cr ...

  9. vsftp 虚拟用户

    首先安装vsftp db-4wiki mkdir -p /opt/ftp 创建用户 sudo useradd virtual -d /opt/ftp -s /bin/false sudo chown ...

  10. LWP::UserAgent介绍1

    require LWP::UserAgent; my $ua = LWP::UserAgent->new; ); $ua->env_proxy; my $response = $ua-&g ...