我们都知道,Java中的锁可以让临界区互斥执行。锁是Java并发编程中最重要的同步机制,锁除了可以让临界区互斥执行外,还可以让释放锁的线程向获取同一个锁的线程发送消息。下面是锁的释放-获取的代码:

  

Class MonitorEx{
int a = 0 ;
public synchronized void writer(){ //1
a++ ; //2 }                   //3 public synchronized void reader(){ //4 int i = a ; //5
......
} //6 }

  假设线程A执行writer()方法,随后线程B执行reader()方法。根据happens-before规则,这个过程包含的happens-before关系有如下3类 :

  (1)根据程序次序规则 : 1 happens-before 2 , 2 happens-before 3 , 4 happens-before 5 , 5 happens-before 6 ;

  (2)根据监视器规则 : 3 happens-before 4 ;

  (3)根据传递依赖规则 : 2 happens-before 5 ;

  happens-before 关系可以转换为如下图的表现形式 :

  

  在上图中,每一个箭头连接的两个点,代表了一个happens-before 关系,短箭头表示的是程序的顺序规则 ; 红色箭头表示监视器规则;黑色长箭头表示的是组合这些规则后提供的happens-before保证 。  

  上图表示线程A在释放了锁之后,随后线程B获取同一个锁,2 happens-before 5 。因此,线程A在释放锁之前所有的可见的共享变量,在B线程获取同一个锁之后,将立刻变得对线程B可见。

  

  以上的介绍是对我们程序员可见的,那么锁的释放和获取在内存中的语义是怎么样的呢 ?

  当线程释放锁时,Java内存模型(Java Memory Modle 简称JMM) 会把该线程对应的本地内存中的共享变量刷新到主内存中,以上面的例子为例,当线程A释放锁后,共享数据的状态示意图如下图所示 :

  当线程获取锁时,JMM会把该线程对应的本地内存置为无效,从而使得被监视器保护的临界区代码必须从主内存中读取共享变量。下图表示锁获取的状态示意图 :

  锁的释放和锁的获取的内存语义可以总结如下:

  □ 线程A释放一个锁,实质上是线程A向接下来要获取同一个锁的某个线程发出了(线程A对共享变量做出修改)消息 。

  □ 线程B获取一个锁,实质上是线程B接收了之前某个线程发出的(在释放这个锁之前对共享变量所做修改)的消息。

  □ 线程A释放锁,随后线程B获取这个锁,这个过程实质上是线程A通过主内存向线程B发送消息 。

  

  

     

  

  

  

Java中锁的内存语义的更多相关文章

  1. Java中锁的实现与内存语义

    目录 1. 概述 2. 锁的内存语义 3. 锁内存语义的实现 4. 总结 1. 概述 锁在实际使用时只是明白锁限制了并发访问, 但是锁是如何实现并发访问的, 同学们可能不太清楚, 下面这篇文章就来揭开 ...

  2. volatile 和锁的内存语义

    一.volatile 的内存语义 1. volatile 的特性 volatile变量自身具有以下特性: 可见性 :对一个volatile变量的读,总是能看到(任意线程)对这个volatile变量最后 ...

  3. JAVA中锁的解决方案

    前言 在上一节中,我们给大家介绍了什么是锁,以及锁的使用场景,我相信大家对锁的定义,以及锁的重要性都有了比较清晰的认识.在这一节中,我们会给大家继续做深入的介绍,介绍JAVA为我们提供的不同种类的锁. ...

  4. Java宝典(四)------Java中也存在内存泄露。

    --Java中会存在内存泄露吗? --如果你想当然的以为Java里有了垃圾回收机制就不会存在内存泄露,那你就错了. Java里也会存在内存泄露! 我们慢慢来分析. 所谓内存泄露就是指一个不再被程序使用 ...

  5. Java 中数组的内存分配

    Java 中数组的内存分配 1.Java 程序在运行时,需要在内存中分配空间.为了提高运算效率,就对空间进行了不同区域的划分,因为每一片区域都有特定的处理数据和内存管理方式. 2.数组基本概念 数组是 ...

  6. Java基础-Java中的堆内存和离堆内存机制

    Java基础-Java中的堆内存和离堆内存机制 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任.

  7. Java中会存在内存泄露吗?请简单描述。

    本文转载自:Java中会存在内存泄漏吗,请简单描述 会.java导致内存泄露的原因很明确:长生命周期的对象持有短生命周期对象的引用就很可能发生内存泄露,尽管短生命周期对象已经不再需要,但是因为长生命周 ...

  8. java中JVM虚拟机内存模型详细说明

    java中JVM虚拟机内存模型详细说明 2012-12-12 18:36:03|  分类: JAVA |  标签:java  jvm  堆内存  虚拟机  |举报|字号 订阅     JVM的内部结构 ...

  9. 并发王者课-铂金1:探本溯源-为何说Lock接口是Java中锁的基础

    欢迎来到<并发王者课>,本文是该系列文章中的第14篇. 在黄金系列中,我们介绍了并发中一些问题,比如死锁.活锁.线程饥饿等问题.在并发编程中,这些问题无疑都是需要解决的.所以,在铂金系列文 ...

随机推荐

  1. Android 测试自定义纯数字软键盘

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools= ...

  2. windows10系统下安装nginx的安装步骤

    打开nginx的官网:http://nginx.org/,下载最新的稳定版本.   下载完成后,解压到你想要解压的文件路径中,我解压到了D盘中,并把文件名改为nginx:进入文件内,打开nginx.e ...

  3. libsvm交叉验证与网格搜索(参数选择)

    首先说交叉验证.交叉验证(Cross validation)是一种评估统计分析.机器学习算法对独立于训练数据的数据集的泛化能力(generalize), 能够避免过拟合问题.交叉验证一般要尽量满足:1 ...

  4. 21. Spring Boot过滤器、监听器【从零开始学Spring Boot】

    转载:http://blog.csdn.net/linxingliang/article/details/52069490 上一篇文章已经对定义Servlet 的方法进行了说明,过滤器(Filter) ...

  5. python(25)- 面向对象补充Ⅰ

    一.如何使用类 1.实例化:创建对象 类名加括号就是实例化,会自动触发__init__函数的运行,可以用它来为每个实例定制自己的特征. 例子一 x=int(10) print(x) python中一切 ...

  6. C# HTTP请求后对gzip页面实现解压缩

    1.通过socket页面请求后的receive内容不能经过string后再进行解压缩处理 会造成错误的gzip幻数报错 推荐使用流处理 2.正确分析返回内容 分割header和页面代码部分 3.对页面 ...

  7. bat+sqlcmd 批量执行脚本

    Hello,此BAT脚本能够帮助开发者将某目录下全部SQL脚本按文件名称依次在指定数据库中批量执行. 不用忍受powershell invoke-sqlcmd 的笨重.在指执行时多一种选择. bat文 ...

  8. vue-导入静态文件

    vue导入静态文件不用像网上说的那么麻烦,其实跟普通Django项目导入类似,vue项目中有一个static文件,将你的静态文件放入到里面,然后引入就好 导入的时候和普通Django程序类似:↓ &l ...

  9. Install Server Backup Manager on CentOS, RHE, and Fedora

    Skip to end of metadata Added by Internal, last edited by Internal on Aug 25, 2014 Go to start of me ...

  10. 用Q-learning算法实现自动走迷宫机器人

    项目描述: 在该项目中,你将使用强化学习算法,实现一个自动走迷宫机器人. 如上图所示,智能机器人显示在右上角.在我们的迷宫中,有陷阱(红色炸弹)及终点(蓝色的目标点)两种情景.机器人要尽量避开陷阱.尽 ...