锁的释放-获取建立的happens before 关系

锁是java并发编程中最重要的同步机制。锁除了让临界区互斥执行外,还可以让释放锁的线程向获取同一个锁的线程发送消息。

下面是锁释放-获取的示例代码:

class MonitorExample {
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 关系可以分为两类:

  1. 根据程序次序规则,1 happens before 2, 2 happens before 3; 4 happens before 5, 5 happens before 6。
  2. 根据监视器锁规则,3 happens before 4。
  3. 根据happens before 的传递性,2 happens before 5。

上述happens before 关系的图形化表现形式如下:

在上图中,每一个箭头链接的两个节点,代表了一个happens before 关系。黑色箭头表示程序顺序规则;橙色箭头表示监视器锁规则;蓝色箭头表示组合这些规则后提供的happens before保证。

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

锁释放和获取的内存语义

当线程释放锁时,JMM会把该线程对应的本地内存中的共享变量刷新到主内存中。以上面的MonitorExample程序为例,A线程释放锁后,共享数据的状态示意图如下:

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

对比锁释放-获取的内存语义与volatile写-读的内存语义,可以看出:锁释放与volatile写有相同的内存语义;锁获取与volatile读有相同的内存语义。

下面对锁释放和锁获取的内存语义做个总结:

  • 线程A释放一个锁,实质上是线程A向接下来将要获取这个锁的某个线程发出了(线程A对共享变量所做修改的)消息。
  • 线程B获取一个锁,实质上是线程B接收了之前某个线程发出的(在释放这个锁之前对共享变量所做修改的)消息。
  • 线程A释放锁,随后线程B获取这个锁,这个过程实质上是线程A通过主内存向线程B发送消息。

ReentrantLock的实现:

class ReentrantLockExample {
int a = 0;
ReentrantLock lock = new ReentrantLock(); public void writer() {
lock.lock(); //获取锁
try {
a++;
} finally {
lock.unlock(); //释放锁
}
} public void reader () {
lock.lock(); //获取锁
try {
int i = a;
……
} finally {
lock.unlock(); //释放锁
}
}
}

在ReentrantLock中,调用lock()方法获取锁;调用unlock()方法释放锁。

ReentrantLock的实现依赖于java同步器框架AbstractQueuedSynchronizer(简称之为AQS)。

AQS使用一个整型的volatile变量(命名为state)来维护同步状态。

深入Java内存模型之阅读理解(2)的更多相关文章

  1. 深入Java内存模型之阅读理解(1)

    Java内存模型的抽象 在java中,所有实例域.静态域和数组元素存储在堆内存中,堆内存在线程之间共享(本文使用“共享变量”这个术语代指实例域,静态域和数组元素).局部变量(Local variabl ...

  2. java内存模型原理阅读总结

    Java内存模型可以理解为在特定操作协议下,对特定的内存或高速缓存进行读写访问的过程抽象.不同架构的物理计算机可以有不一样的内存模型,java虚拟机也有自己的内存模型,java虚拟机规范中试图定义一种 ...

  3. java内存模型:简单理解

    1.Java内存模型(Java Memory Model,JMM) 2.JMM定义了线程和主内存之间的抽象关系: 线程之间的共享变量存储在主内存(main memory)中,每个线程都有一个私有的本地 ...

  4. Java内存模型的深入理解

    基础 并发编程的模型分类 在并发编程需要处理的两个关键问题是:线程之间如何通信 和 线程之间如何同步. 通信 通信 是指线程之间以何种机制来交换信息.在命令式编程中,线程之间的通信机制有两种:共享内存 ...

  5. 《成神之路-基础篇》JVM——Java内存模型(已完结)

    Java内存模型 本文是<成神之路系列文章>的第一篇,主要是关于JVM的一些介绍. 持续更新中 Java内存模型 JVM内存结构 VS Java内存模型 VS Java对象模型(Holli ...

  6. 《Java并发编程实战》第十六章 Java内存模型 读书笔记

    Java内存模型是保障多线程安全的根基,这里不过认识型的理解总结并未深入研究. 一.什么是内存模型,为什么须要它 Java内存模型(Java Memory Model)并发相关的安全公布,同步策略的规 ...

  7. Java并发(二):Java内存模型

    一.硬件内存架构 一个现代计算机通常由两个或者多个CPU.其中一些CPU还有多核.每个CPU在某一时刻运行一个线程是没有问题的.如果你的Java程序是多线程的,在你的Java程序中每个CPU上一个线程 ...

  8. 并发编程-Java内存模型

    将之前看过的关于并发编程的东西总结记录一下,本文简单记录Java内存模型的相关知识. 1. 并发编程两个关键问题 并发编程中,需要处理两个关键问题:线程之间如何通信及线程之间如何同步. (1)在命令式 ...

  9. Java并发编程:Java内存模型JMM

    简介 Java内存模型英文叫做(Java Memory Model),简称为JMM.Java虚拟机规范试图定义一种Java内存模型来屏蔽掉各种硬件和系统的内存访问差异,实现平台无关性. CPU和缓存一 ...

随机推荐

  1. Python开源框架、库、软件和资源大集合

    A curated list of awesome Python frameworks, libraries, software and resources. Inspired by awesome- ...

  2. EBS R12视图打不到数据

    兩個原因引起的,一個是語言,一個是oualter session set nls_language ='AMERICAN';alter session set nls_language='SIMPLI ...

  3. RxJava2 源码解析(一)

    概述 最近事情太多了,现在公司内部的变动,自己岗位的变化,以及最近决定找工作.所以博客耽误了,准备面试中,打算看一看RxJava2的源码,遂有了这篇文章. 不会对RxJava2的源码逐字逐句的阅读,只 ...

  4. iOS开发-NSUndoManager撤销(undo)和重做(redo)

    程序开发中我们经常会用到的两个快捷键Ctrl+Z和Ctrl+C,撤销和复制,Cocoa开发也可以实现这两个操作,为我们提供非常简单的操作类NSUndoManger,也可以称之为撤销管理器,NSUndo ...

  5. python unknown error: DevToolsActivePort file doesn't exist 问题解决

    解决方案: from selenium.webdriver.chrome.options import Options chrome_options = Options() chrome_option ...

  6. (转)GrabPass捕捉屏幕纹理

    转自:http://blog.sina.com.cn/s/blog_89d90b7c0102va4m.html 最近在看热扭曲效果,里面用到了GrabPass. 之前看过官方翻译版本的说明http:/ ...

  7. IOS Using UIAlertView to show alerts

    UIAlertView in other words, it's a dialog box. You want to show a message or ask user to confirm an ...

  8. C# System.IO.FileAccess

    字段 Read 1 对文件的读访问. 可从文件中读取数据. 与 Write 组合以进行读写访问. ReadWrite 3 对文件的读写访问权限. 可从文件读取数据和将数据写入文件. Write 2 文 ...

  9. Promise.then的第二个参数与catch的区别

    1.异常捕获 getJSON("/post/1.json").then(function(post) { return getJSON(post.commentURL); }).t ...

  10. Qt下多线程日之类

    刚google到了,晚上回去试一下! 代码地址 https://gitorious.org/cutelogger/cutelogger/source/e3c2745c6c5f38896f87472e0 ...