《java并发编程实战》读书笔记13--Java内存模型,重排序,Happens-Before

时间:2022-02-01 13:18:42

第16章 Java内存模型

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

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

《java并发编程实战》读书笔记13--Java内存模型,重排序,Happens-Before

《java并发编程实战》读书笔记13--Java内存模型,重排序,Happens-Before

16.1.1 平台的内存模型

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

16.1.2 重排序

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

《java并发编程实战》读书笔记13--Java内存模型,重排序,Happens-Before

《java并发编程实战》读书笔记13--Java内存模型,重排序,Happens-Before

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

16.1.3 Java内存模型简介

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

《java并发编程实战》读书笔记13--Java内存模型,重排序,Happens-Before

《java并发编程实战》读书笔记13--Java内存模型,重排序,Happens-Before

16.1.4 借助同步

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

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

《java并发编程实战》读书笔记13--Java内存模型,重排序,Happens-Before

《java并发编程实战》读书笔记13--Java内存模型,重排序,Happens-Before

《java并发编程实战》读书笔记13--Java内存模型,重排序,Happens-Before

《java并发编程实战》读书笔记13--Java内存模型,重排序,Happens-Before

16.2 发布

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

16.2.1 不安全的发布

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

《java并发编程实战》读书笔记13--Java内存模型,重排序,Happens-Before

16.2.2 安全地发布

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

16.2.3 安全初始化模式

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

《java并发编程实战》读书笔记13--Java内存模型,重排序,Happens-Before

《java并发编程实战》读书笔记13--Java内存模型,重排序,Happens-Before

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

《java并发编程实战》读书笔记13--Java内存模型,重排序,Happens-Before

《java并发编程实战》读书笔记13--Java内存模型,重排序,Happens-Before

16.2.4 双重检查锁

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

16.3 初始化过程中的安全性


小结:

《java并发编程实战》读书笔记13--Java内存模型,重排序,Happens-Before


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

《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. wait、notify、sleep、interrupt对比分析

    对比分析Java中的各个线程相关的wait().notify().sleep().interrupt()方法 方法简述 Thread类 sleep:暂停当前正在执行的线程:(类方法) yield:暂停 ...

  2. 数论 UVA 10791

    这道题目是关于满足同意最小公倍数的所有数对中两数之和的最小值. 题目大意是给你一个数n,要求你求出在所有以n为最小公倍数的数对中两数之和的最小值. 方法:将n进行质因数分解,再将所有分解出的质因子加起 ...

  3. IOS Quartz 各种绘制图形用法---实现画图片、写文字、画线、椭圆、矩形、棱形等

    // Only override drawRect: if you perform custom drawing. // An empty implementation adversely affec ...

  4. SRM 406&lpar;1-250pt&comma; 1-500pt&rpar;

    DIV1 250pt 题意:有几家宠物店,vecort<int>A表示每家宠物店含有小狗占小狗总数的百分比.现在要做扇形统计图统计每家店的小狗百分比,如下图,问作出来的扇形统计图中最多含有 ...

  5. Redis可视化工具Redis Desktop Manager使用

    Redis可视化工具,RedisDesktopManager 没错,它开源的,托管在github上:https://github.com/uglide/RedisDesktopManager 还不错, ...

  6. 如何将md文件转换成带目录的html文件

    配置环境node 去官网下一个node安装包,下一步下一步: 由于现在的node都自带npm,直接 npm install i5ting_toc 这样安装好了i5ting_toc这个包, 进入你实现准 ...

  7. HTTP协议的简单介绍

    前传:HTTP协议的演变过程 HTTP(HyperText Transfer Protocol)协议是基于TCP的应用层协议,它不关心数据传输的细节,主要是用来规定客户端和服务端的数据传输格式,最初是 ...

  8. JAVA类的方法调用和变量&lpar;全套&rpar;

    一.类的分类: 1.普通类 2.抽象类(含有抽象方法的类) 3.静态类(不需要实例化,就可以使用的类) 二.方法的分类: 1.私有方法(只有类的内部才可以访问的方法) 2.保护方法(只有类的内部和该该 ...

  9. NDK开发环境安装,CDT安装,Cygwin安装

     1.为eclipse增加c和c++的开发插件 Help中的install new software 选择 Helios-http://download.eclipse.org/release/h ...

  10. R语言实战(四)—— 基本数据管理

    一.基础操作 1.根据数据信息,创建数据框 > manager <- c(1,2,3,4,5) > date <- c("10/24/08","1 ...