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

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

根据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. 连接pgsql

    package com.jpzhutech.select; import java.sql.Connection; import java.sql.DriverManager; import java ...

  2. RockMongo 安装

    1. yum install php-pecl-http php 2. yum install httpd 3. yum install php-devel 4. pecl install mongo ...

  3. php取整

    php取整的方法一共有4中,分别是ceil(),floor(),round(),intval(). 1.ceil--向上取整,即不小于当前的下一个整数,如果有小数则进一位. 返回的是float类型 & ...

  4. PhpSrom安装xdebug

    1.php需要安装xdebug,这样能支持调试. 下载地址:http://www.xdebug.org/download.php,若不清楚下载版本,可将phpinfo的信息复制到下载地址页面的cust ...

  5. Android 不能返回 parent Activity 的问题

    使用 ActionBar,开启返回按钮: 在 Activity 的 onCreate 中添加下面代码 getSupportActionBar().setDisplayHomeAsUpEnabled(t ...

  6. CentOS 6.5静态IP的设置(NAT和桥接都适用)

    CentOS 6.5静态IP的设置(NAT和桥接都适用) 为了方便,用Xshell来.并将IP设置为静态的.因为,在CentOS里,若不对其IP进行静态设置的话,则每次开机,其IP都是动态变化的,这样 ...

  7. 怎样成为PHP 方向的一个合格的架构师(转)

    突然看到这篇文章, 值得反省, 乐在其中, 在接下来的发展中不被淘汰的都来看看, 如何成为一个架构师先明确这里所指的PHP工程师,是指主要以PHP进行Web系统的开发,没有使用其的语言工作过.工作经验 ...

  8. Documention

    Object.bool Does the object exist? Object.name Components share the same name with the game object a ...

  9. TCP三次握手中,为什么需要第三次握手?

    为什么客户端A还要发送一次确认呢?(为什么需要第三次握手) 这主要是为了防止已失效的连接请求报文段突然又传送到了B(服务器端),因而产生错误. 所谓"已失效的连接请求报文段"是这样 ...

  10. 数据库及SQL优化

    一.数据库结构的设计 如果不能设计一个合理的数据库模型,不仅会增加客户端和服务器段程序的编程和维护的难度,而且将会影响系统实际运行的性能.所以,在一个系统开始实施之前,完备的数据库模型的设计是必须的. ...