typora-root-url: ./

CPU多核并发缓存架构

JMM(Java线程内存模型)底层实现原理

基于CPU缓存模型建立的,屏蔽掉了底层不同计算机的区别。

所有的共享变量都存储在主内存。每条线程还有自己的工作内存。线程对变量的所有操作都必须在工作内存中进行,而不能直接读写主内存中的变量。

JMM数据原子操作

  • read(读取):从主内存读取数据到工作内存中,以便load
  • load(载入):将主内存读取到的数据写入工作内存
  • use(使用):从工作内存读取数据来计算
  • assign(赋值):将计算好的值重新赋值到工作内存中
  • store(存储):将工作内存数据写入主内存
  • write(写入):将store的变量值赋值给主内存中的变量
  • lock(锁定):将主内存变量加锁,标识为线程独占状态
  • unlock(解锁):将主内存变量解锁,解锁后其他线程可以锁定该变量

深入汇编语言底层理解volatile关键字

共享变量改变,但是副本没有改变!

例子:Java

private static boolean initFlag = false;

public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("waiting data...");
while(!initFlag) { }
System.out.println("======success"); // 这句不会输出
}
}).start(); Thread.sleep(2000); new Thread(new Runnable() {
@Override
public void run() {
System.out.println("prepareing data...");
initFlag = true;
System.out.println("======prepare data end...");
}
}).start();
}

JMM缓存不一致问题-修改:

private static volatile boolean initFlag = false;

System.out.println("======success"); //打印成功

简单理解为副本之间可以互相感知共享变量的改变,保证可变性。(线程之间通信)

volatile实现原理

总线加锁(性能太低)

CPU从主内存读取数据到高速缓存,会在总线对这个数据加锁,这样其他CPU没法去读或写这个数据,直到这个CPU使用完数据释放锁之后其他CPU才能读取该数据。

MESI缓存一致性协议

多个CPU从主内存读取同一个数据到各自的高速缓存,当其中某个CPU修改了缓存里的数据,该数据会马上同步回主内存,其它CPU通过总线嗅探机制可以感知到数据的变化从而将自己缓存里的数据失效。

volatile缓存可见性实现原理

底层实现主要是通过汇编lock前缀指令,它会锁定这块内存区域的缓存(缓存行锁定)并回写到主内存。

并发编程:可见性、原子性与有序性

有序性
for(int i = 0; i < 100000; i++) {
x = 0;
y = 0;
Thread one = new Thread(new Runnable() {
public void run() {
int a = y; // 3
x = 1; // 1
}
}); Thread other = new Thread(new Runnable() {
public void run() {
int b = x; // 4
y = 1; // 2
}
})
}

指令重排,导致程序问题。volatile!提示不要指令重排。

可见性

可见性,指当一条线程修改了这个变量的值,新值对于其他线程来说是可以立即得知的。

原子性

volatile保证可见性与有序性,但是不保证原子性,保证原子性需要借助synchronized这样的锁机制。

private static volatile int num = 0;

public static void main(String[] args) {
Thread[] threads = new Thread[10];
for(Thread t : threads) {
t = new Thread(new Runnable() {
@Override
public void run() {
for(int i = 0; i < 1000; i++) {
increase(); // num++;
}
}
});
t.start();
} for(Thread t : threads) {
t.join();
} System.out.println(num); // <=10000
} ======字节码在这里=====
getstatic
iconst_1
iadd
putstatic

在自己加值的时候(iconst_1或者iadd),其他线程可能已经把值加上去了,所以自己加的是一个过期的数据。

总结

volatile的两个语义:

  1. 可见性
  2. 禁止指令重排序优化

jvm(6):JMM的更多相关文章

  1. 深入理解JVM内幕:从基本结构到Java 7新特性

    转自:http://www.importnew.com/1486.html 每个Java开发者都知道Java字节码是执行在JRE((Java Runtime Environment Java运行时环境 ...

  2. JVM总括:目录

    JVM总括:目录 JVM总括一-JVM内存模型 JVM总括二-垃圾回收:GC Roots.回收算法.回收器 JVM总括三-字节码.字节码指令.JIT编译执行 JVM总括四-类加载过程.双亲委派模型.对 ...

  3. JVM内存:年轻代、老年代、永久代(推荐 转)

    参考文章: 1.Java 新生代.老年代.持久代.元空间 2.Java内存与垃圾回收调优 3.方法区的Class信息,又称为永久代,是否属于Java堆? Java 中的堆是 JVM 所管理的最大的一块 ...

  4. JVM(三):深入分析Java字节码-上

    JVM(三):深入分析Java字节码-上 字节码文章分为上下两篇,上篇也就是本文主要讲述class文件存在的意义,以及其带来的益处.并分析其内在构成之一 ---字节码,而下篇则从指令集方面着手,讲解指 ...

  5. JVM(八):Java 对象模型

    JVM(八):Java 对象模型 本文将学习对象是如何创建的,对象的内存布局,以及如何定位访问一个对象. 对象创建 当虚拟机碰到一个new指令时,首先检查指令参数能否在常量池中定位一个类的符号引用,并 ...

  6. JVM(十一):内存分配

    JVM(十一):内存分配 在前面的章节中,我们花了大量的篇幅去介绍 JVM 内的内存布局.对象在内存中的状态.垃圾回收的算法和具体实现等.今天让我们探讨一下对象是如何分配内存的. 堆内存划分 前面说过 ...

  7. 深入理解JVM内幕:从基本结构到Java 7新特性[转]

    英文原文:cubrid,编译:ImportNew - 朱伟杰 译文链接:http://www.importnew.com/1486.html [如需转载,请在正文中标注并保留原文链接.译文链接和译者等 ...

  8. Java并发指南5:JMM中的final关键字解析

    本文转载自互联网,侵删   与前面介绍的锁和volatile相比较,对final域的读和写更像是普通的变量访问.对于final域,编译器和处理器要遵守两个重排序规则: 在构造函数内对一个final域的 ...

  9. JVM探秘:MAT分析内存溢出

    本系列笔记主要基于<深入理解Java虚拟机:JVM高级特性与最佳实践 第2版>,是这本书的读书笔记. MAT是分析Java堆内存的一个工具,全称是 The Eclipse Memory A ...

随机推荐

  1. Arduino上搭建ESP8266环境

    我尝试了各种方法都无法在Arduino上安装ESP8266的环境,最后发现离线安装最稳妥. 1. 下载安装包,提取码:pktw 2. 将安装包内所有文件拷贝到C:\Users\Administrato ...

  2. 【spring boot】SpringBoot初学(7)– 多数据源及其事务

    前言 github: https://github.com/vergilyn/SpringBootDemo 代码位置: 参考: Spring Boot Reference Guide , §77.2 ...

  3. 《C++面向对象程序设计》第6章课后编程题2拓展

    设计一个程序,其中有3个类CBank.BBank.GBank,分别为中国银行类,工商银行类和农业银行类.每个类都包含一个私有数据成员balance用于存放储户在该行的存款数,另有一个友元函数Total ...

  4. gulp常用插件之gulp-notify使用

    更多gulp常用插件使用请访问:gulp常用插件汇总 gulp-notify这是一款gulp通知插件. 更多使用文档请点击访问gulp-notify工具官网. 安装 一键安装不多解释 npm inst ...

  5. Educational Codeforces Round 82 (Rated for Div. 2)

    题外话 开始没看懂D题意跳了,发现F题难写又跳回来了.. 语文好差,码力好差 A 判第一个\(1\)跟最后一个\(1\)中\(0\)的个数即可 B 乘乘除除就完事了 C 用并查集判一下联通,每个联通块 ...

  6. Java链表常见操作【剑指Offer】03:从尾到头打印链表

    题目描述 输入一个链表,按链表从尾到头的顺序返回一个ArrayList. 题解一:递归 /* 在最后一次递归方法返回以后,每一层的递归方法都会做一个arrayList.add(listNode.val ...

  7. [POI2008] PLA-Postering - 单调栈

    给你 \(n\) 个相连的矩形建筑,让你用最少海报把他们覆盖掉,海报不能重叠,也不可以高出被覆盖的矩形. Solution 考虑维护一个单调递增的栈,每次插入时弹掉所有比自己高的,如果自己和末端一样高 ...

  8. ansi sql 语法 切换为 oracle 语法

        语句粘贴到 工作表 打开查询构建器 勾选 创建oracle连接 over     sql dev 的语法设置调整,否则表别名会右对齐   下面是 转换后的结果,是不是看得舒服多了

  9. JS 百度地图-右键菜单

    JS 百度地图-右键菜单 /*-----------------标注右键删除-------------------------*/ var markerMenu = new BMap.ContextM ...

  10. MyBatis 中 Mapper 接口的使用原理

    MyBatis 中 Mapper 接口的使用原理 MyBatis 3 推荐使用 Mapper 接口的方式来执行 xml 配置中的 SQL,用起来很方便,也很灵活.在方便之余,想了解一下这是如何实现的, ...