什么是内存模型

  • JMM(Java内存模型)规定了JVM必须遵循一组最小保证,这组保证规定了对变量的写入操作在何时将对其他线程可见。
  • JMM为程序中所有的操作定义了一个偏序关系,称为Happens-Before。两个操作缺乏Happens-Before关系,则Jvm会对它们进行任意的重排序。

    Happends-Before的规则包括:

    1. 程序顺序规则。若程序中操作A在操作B之前,则线程中操作A在操作B之前执行。

    2. 监视器锁规则。在同一监视器锁上的解锁操作必须在加锁操作之前执行。如图所示,

    3. volatile变量规则。对volatile变量的写操作必须在读操作之前执行。

    4. 线程启动规则。Thread.start必须在线程中执行的操作之前被调用。

    5. 线程关闭规则。线程中的任何操作必须在其他线程检测到该线程结束之前执行,或者从Thread.join中返回,或调用Threas.isAlive返回false。

    6. 中断规则。当一个线程在另一个线程上调用interrupt时,必须在被中断线程检测到interrupt调用之前执行。

    7. 终结器规则。对象的构造函数必须在启动该对象的终结器之前执行完成。

    8. 传递性。如果操作A在操作B之前执行,操作B在操作C之前执行,则操作A必须在操作C之前执行。

    双重检查加锁

  1. /**
  2.  * 双重检查加锁, 不安全,
  3.  * 线程可能看到无效的值, 可加上volatile修饰
  4.  */
  5. public class DoubleCheckedLocking {
  6.     private static Object resource;
  7.  
  8.     public static Object getInstance(){
  9.         if (resource == null){
  10.             synchronized (DoubleCheckedLocking.class){
  11.                 if (resource == null){
  12.                     resource = new Object();
  13.                 }
  14.             }
  15.         }
  16.         return resource;
  17.     }
  18. }

如果不使用volatile,可能看到对象的错误或者无效状态。

原因:因为JMM会在发布对象的引用和内部构造函数之间进行重排序,也就是说先把栈中对象的引用指向堆中的位置,但是由于重排序堆中的构造函数还没有执行完。但是使用volatile可以避免这种重排序。

因为接下来要看《Java并发编程的艺术》,里面有大量的章节讲述内存模型的只是,而这本书的这一章节比较晦涩,所以就不细看了。

Java并发编程实战 第16章 Java内存模型的更多相关文章

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

    第16章 Java内存模型 终于看到这本书的最后一章了,嘿嘿,以后把这本书的英文版再翻翻.这本书中尽可能回避了java内存模型(JMM)的底层细节,而将重点放在一些高层设计问题,例如安全发布,同步策略 ...

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

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

  3. Java并发编程实战---第六章:任务执行

    废话开篇 今天开始学习Java并发编程实战,很多大牛都推荐,所以为了能在并发编程的道路上留下点书本上的知识,所以也就有了这篇博文.今天主要学习的是任务执行章节,主要讲了任务执行定义.Executor. ...

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

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

  5. 【java并发编程实战】第一章笔记

    1.线程安全的定义 当多个线程访问某个类时,不管允许环境采用何种调度方式或者这些线程如何交替执行,这个类都能表现出正确的行为 如果一个类既不包含任何域,也不包含任何对其他类中域的引用.则它一定是无状态 ...

  6. Java并发编程实战 第8章 线程池的使用

    合理的控制线程池的大小: 下面内容来自网络.不过跟作者说的一致.不想自己敲了.留个记录. 要想合理的配置线程池的大小,首先得分析任务的特性,可以从以下几个角度分析: 任务的性质:CPU密集型任务.IO ...

  7. Java并发编程实战 第3章 对象的共享

    可见性 可见性是由于java对于多线程处理的内存模型导致的.这似乎是一种失败的设计,但是JVM却能充分的利用多核处理器的强大性能,例如在缺乏同步的情况下,Java内存模型允许编译器对操作顺序进行重排序 ...

  8. JAVA并发编程实战---第三章:对象的共享

    在没有同步的情况下,编译器.处理器以及运行时等都可能对操作的执行顺序进行一些意想不到的调整.在缺乏足够同步的多线程程序中,要对内存操作的执行顺序进行判断几乎无法得到正确的结果. 非原子的64位操作 当 ...

  9. 【java并发编程实战】第二章:对象的共享

    1.重要的属性 可见性,不变性,原子性 1.1可见性 当一个线程修改某个对象状态的时候,我们希望其他线程也能看到发生后的变化. 在没有同步的情况下,编译器和处理器会对代码的执行顺序进行重排.以提高效率 ...

随机推荐

  1. sql四种连接方式

    1.内连接(inner  join)只有两个表相匹配的行才能在结果集中显示出来2.左连接(left  join)以左表为主,左表所有的数据都会在结果集中出现,右表根据左表对应的数据显示,与左表匹配的数 ...

  2. JavaEE-实验一 Java常用工具类编程

    该博客仅专为我的小伙伴提供参考而附加,没空加上代码具体解析,望各位谅解 1.  使用类String类的分割split 将字符串  “Solutions to selected exercises ca ...

  3. linux LVM分区查看dm设备

    linux LVM分区查看dm设备 在linux中iostat -d查看磁盘状态时,有的会有如下dm-0,dm-1的条目. Device:            tps    kB_read/s   ...

  4. Stream流实现斐波那契数列

    1.前言 我们都知道斐波那契数列有很多种实现方法,在jdk1.8以前没有流操作,只能通过递归或者迭代等其他方式来实现斐波那契数列, 但是jdk1.8以后,有了流操作,我们就可以使用流来实现斐波那契数列 ...

  5. python__007内置函数

    本文摘自:https://docs.python.org/3/library/functions.html?highlight=built#ascii     内置功能     abs() delat ...

  6. cocos2dx[3.2](5) 屏幕适配

    1.两个分辨率 1.1.窗口分辨率 在AppDelegate.cpp中有个设置窗口分辨率的函数.该函数是设置了我们预想设备的屏幕大小,也就是应用程序窗口的大小. // glView->setFr ...

  7. 【HTTP】四、HTTP协议常见问题

      HTTP协议是一个非常重要的应用层协议,在面试中有很多关于这方面的问题,这里做一个总结,大部分都在前面的文章中提到了,没提到的这里做一个介绍. 1.HTTP协议的基本原理.工作流程   HTTP协 ...

  8. 【VS开发】如何移植对话框?

    [VS开发]如何移植对话框? 标签:[VS开发] 问题描述:当开发好一个可视化界面的时候,想将其移植到另外的工程中,这个时候希望能够导出对话框资源,好直接在另一个工程中进行编辑,而不用再次编辑对话框上 ...

  9. vue ----》实现打印功能

    1.安装打印相关依赖 cnpm install vue-print-nb --save 2.安装后,在main.js文件中引入 import Print from 'vue-print-nb' Vue ...

  10. (转)在Kubernetes集群中使用JMeter对Company示例进行压力测试

    背景 压力测试是评估应用性能的一种有效手段.此外,越来越多的应用被拆分为多个微服务而每个微服务的性能不一,有的微服务是计算密集型,有的是IO密集型. 因此,压力测试在基于微服务架构的网络应用中扮演着越 ...