第16章 Java内存模型

终于看到这本书的最后一章了,嘿嘿,以后把这本书的英文版再翻翻。这本书中尽可能回避了java内存模型(JMM)的底层细节,而将重点放在一些高层设计问题,例如安全发布,同步策略等。它们的安全性都来自于JMM。本章将介绍Java内存模型的底层需求以及所提供的保证。

16.1 什么是内存模型,为什么需要它

16.1.1 平台的内存模型

在共享内存的多处理体系架构中,每个处理器都拥有自己的缓存,并且定期地与住内存进行协调。在不同的处理器架构中提供了不同级别的缓存一致性。要想确保每个处理器在任意时刻都能知道其他处理器正在进行的工作,将需要非常大的开销。在大多数时间里,这种信息是不必要的,因此处理器会适当放宽存储一致性保证,以换取性能的提升。在架构定义的内存模型中将告诉应用程序可以从内存系统中获得怎样的保证,此外还定义了一些特殊的指令(称为内存栅栏或栅栏),当需要共享数据时,这些指令就能实现额外的存储协调保证。为了使java开发人员无需关心不同架构上内存模型之间的差异,Java还提供了自己的内存模型,并且JVM通过在适当位置上插入内存栅栏来屏蔽JMM与底层平台内存模型之间的差异

16.1.2 重排序

JMM可以使不同线程看到的操作执行顺序是不同的,从而导致在缺乏同步的情况下,要推断操作的执行顺序将变得更加复杂。各种操作延迟或者看似乱序执行的不容原因,都可以归为重排序。

同步将限制编译器,运行时和硬件对内存操作重排序的方式,从而在实施重排序时不会破坏JMM提供的可见性保证。

16.1.3 Java内存模型简介

JMM为程序中所有的操作提供了一个偏序关系,称之为Happens-before。要想保证执行操作B的线程看到操作A的结果,那么A和B之间必须满足Happens-before关系。如果两个操作之间缺乏Happens-Before关系,那么JVM可以对它们任意地重排序。

16.1.4 借助同步

由于Happens-Before的排序功能很强大,因此有时候可以"借助"(Piggyback)现有同步机制的可见性属性。这需要将Happens-Before的程序规则与其他某个顺序规则结合起来,从而对某个未被锁保护的变量的访问操作进行排序。这项技术对语句的顺序非常敏感,因此很容易出错。它是一项高级技术,并且只有当需要最大限度提升某些类(例如ReentrantLock)的性能时,才应该使用这项技术。

在FutureTask的保护方法AbstractQueuedSynchronizer中说明了如何使用这种“借助”技术。

16.2 发布

第3章介绍了如何安全地发布或者不正确地发布一个对象。其中介绍的各种安全技术,它们的安全性都来自于JMM提供的保证,而造成不正确发布的真正原因,就是在“发布一个共享对象”与“另一个线程访问该对象”之间缺少一种Happens-Before排序。

16.2.1 不安全的发布

如果无法确保发布共享引用的操作在另一个线程加载该共享引用之前执行,那么对新对象引用的写入操作将与对象中各个域的写入操作重排序。在这种情况下,另一个线程可能看到对象引用的最新值,但同时也将看到对象的某些或全部状态中包含的是无效值,即一个被部分构造的对象。错误的延迟初始化将导致不正确的发布,如程序16-3所示:

16.2.2 安全地发布

第3章介绍的安全发布常用模式可以确保被发布对象对于其他线程是可见的,因为它们保证发布对象的操作将在使用对象的线程开始使用该对象的引用之前执行。

16.2.3 安全初始化模式

有时候需要推迟一些高开销的对象初始化操作,并且只有当使用这些对象时才进行初始化。在程序清单16-4中通过将getResource方法声明为synchronized可以修复UnsafeLazyInitialization中的问题。由于getInstance的代码路径很短,因此如果geiInstance没有被多个线程频繁调用,那么在SafeLazyInitialization上不会存在激烈的竞争。

如程序16-5所示,通过提前初始化,避免了在每次调用SafeLazyInitialization中的getInstance时所产生的同步开销。在程序16-6的“延迟初始化占位类模式”中使用了一个专门的类来初始化Resource。JVM将推迟ResourceHolder的初始化操作,直到开始使用这个类时才初始化,并且由于通过一个静态初始化来初始化Resource,因此不需要额外的同步。

16.2.4 双重检查锁

DCL,已经被广泛的废弃了,pass

16.3 初始化过程中的安全性


小结:


终于把这本书看得差不多了....,呼呼呼,真不容易,总算又完结了一件事。这本书大概现在也只搞懂了一半左右,毕竟只看了一遍,糟糕的翻译质量为本书的阅读添加了不少的难度。除此之外,这本书理论大于实践,代码实践部分并不多,书中有很多前提知识是假定你已经知道的,所以适合有一定基础的人看。以后有时间把英文版拿来看看,最关键的是要在实践中运用这些知识才行。

《java并发编程实战》读书笔记13--Java内存模型,重排序,Happens-Before的更多相关文章

  1. Java并发编程实战 读书笔记(一)

    最近在看多线程经典书籍Java并发变成实战,很多概念有疑惑,虽然工作中很少用到多线程,但觉得还是自己太弱了.加油.记一些随笔.下面简单介绍一下线程. 一  线程与进程   进程与线程的解释   个人觉 ...

  2. Java并发编程实战 读书笔记(二)

    关于发布和逸出 并发编程实践中,this引用逃逸("this"escape)是指对象还没有构造完成,它的this引用就被发布出去了.这是危及到线程安全的,因为其他线程有可能通过这个 ...

  3. 那些年读过的书《Java并发编程实战》和《Java并发编程的艺术》三、任务执行框架—Executor框架小结

    <Java并发编程实战>和<Java并发编程的艺术>           Executor框架小结 1.在线程中如何执行任务 (1)任务执行目标: 在正常负载情况下,服务器应用 ...

  4. 《java并发编程实战》笔记

    <java并发编程实战>这本书配合并发编程网中的并发系列文章一起看,效果会好很多. 并发系列的文章链接为:  Java并发性和多线程介绍目录 建议: <java并发编程实战>第 ...

  5. java并发编程实战《二》java内存模型

    Java解决可见性和有序性问题:Java内存模型 什么是 Java 内存模型? Java 内存模型是个很复杂的规范,可以从不同的视角来解读,站在我们这些程序员的视角,本质上可以理解为, Java 内存 ...

  6. Java多线程编程实战读书笔记(一)

    多线程的基础概念本人在学习多线程的时候发现一本书——java多线程编程实战指南.整理了一下书中的概念制作成了思维导图的形式.按照书中的章节整理,并添加一些个人的理解.

  7. Java并发编程实战 第16章 Java内存模型

    什么是内存模型 JMM(Java内存模型)规定了JVM必须遵循一组最小保证,这组保证规定了对变量的写入操作在何时将对其他线程可见. JMM为程序中所有的操作定义了一个偏序关系,称为Happens-Be ...

  8. Java并发编程艺术读书笔记

    1.多线程在CPU切换过程中,由于需要保存线程之前状态和加载新线程状态,成为上下文切换,上下文切换会造成消耗系统内存.所以,可合理控制线程数量. 如何控制: (1)使用ps -ef|grep appn ...

  9. Java并发编程实践读书笔记(1)线程安全性和对象的共享

    2.线程的安全性 2.1什么是线程安全 在多个线程访问的时候,程序还能"正确",那就是线程安全的. 无状态(可以理解为没有字段的类)的对象一定是线程安全的. 2.2 原子性 典型的 ...

  10. Java并发编程的艺术(四)——JMM、重排序、happens-before

    什么是JMM JMM就是Java内存模型.目的是为了屏蔽系统和硬件的差异,让同一代码在不同平台下能够达到相同的访问结果.规定了线程和内存之间的关系. 内存划分 JMM规定了内存主要划分为主内存和工作内 ...

随机推荐

  1. (ex)BSGS题表

    学了一下BSGS大概知道他是什么了,但是并没有做什么难题,所以也就会个板子.普通的BSGS,我还是比较理解的,然而exBSGS我却只理解个大概,也许还会个板子......(这个东西好像都会有一群恶心的 ...

  2. GYM 101875 2018 USP-ICMC

    3月自训 (1):10/12 A: 题意:每个人可以连边,最远连到第(i+k)%n个人,边权为这个人与另一个人连边距离,求生成一颗最大生成树的权值和是多少 题解:可以证明的是,我们每一个人都向接下来的 ...

  3. Android LayoutInflater深度解析

    1. 题外话 相信大家对LayoutInflate都不陌生,特别在ListView的Adapter的getView方法中基本都会出现,使用inflate方法去加载一个布局,用于ListView的每个I ...

  4. [洛谷P2491] [SDOI2011]消防

    洛谷题目链接:[SDOI2011]消防 题目描述 某个国家有n个城市,这n个城市中任意两个都连通且有唯一一条路径,每条连通两个城市的道路的长度为zi(zi<=1000). 这个国家的人对火焰有超 ...

  5. centos6.8+openvpn实现账户密码连接(通过端口映射的方式)

    #搭建openvpn(编译安装) 初始化环境 #update epel mirror yum install wget -y cd /etc/yum.repos.d && rm -rf ...

  6. 「6月雅礼集训 2017 Day11」delight

    [题目大意] 有$n$天,每天能吃饭.睡觉.什么事也不干 每天吃饭的愉悦值为$e_i$,睡觉的愉悦值为$s_i$,什么都不干愉悦值为0. 要求每连续$k$天都要有至少$E$天吃饭,$S$天睡觉. 求最 ...

  7. Spring Cloud的基本认识和使用Spring Cloud的基本教程(山东数漫江湖)

    认识Spring Cloud Spring Cloud简单来说就是一个微服务相关的框架,至于什么是微服务,简单来说就是一个整体项目由多个单独运行的小项目构成,每个小项目负责一个或多个功能,每个小项目有 ...

  8. web_一些常用的线上脚本地址记录(个人使用)

    1.jquery <script src="http://code.jquery.com/jquery-1.4.1.min.js"></script> 2. ...

  9. Html5_sessionStrong和localStorage的灵活使用

    谈谈这两个属性sessionStrong和localStorage是Html5新增点属性,用来记录一些数据在浏览器. 两者的区别sessionStrong存储的数据是暂时的,浏览器关掉后,存储下来的数 ...

  10. Ribbon的主要组件与工作流程

    一:Ribbon是什么? Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法,将Netflix的中间层服务连接在一起.Ribbon客户端组件提供一系列完善的配置项如连接 ...