jvm(6):JMM
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的两个语义:
- 可见性
- 禁止指令重排序优化
jvm(6):JMM的更多相关文章
- 深入理解JVM内幕:从基本结构到Java 7新特性
转自:http://www.importnew.com/1486.html 每个Java开发者都知道Java字节码是执行在JRE((Java Runtime Environment Java运行时环境 ...
- JVM总括:目录
JVM总括:目录 JVM总括一-JVM内存模型 JVM总括二-垃圾回收:GC Roots.回收算法.回收器 JVM总括三-字节码.字节码指令.JIT编译执行 JVM总括四-类加载过程.双亲委派模型.对 ...
- JVM内存:年轻代、老年代、永久代(推荐 转)
参考文章: 1.Java 新生代.老年代.持久代.元空间 2.Java内存与垃圾回收调优 3.方法区的Class信息,又称为永久代,是否属于Java堆? Java 中的堆是 JVM 所管理的最大的一块 ...
- JVM(三):深入分析Java字节码-上
JVM(三):深入分析Java字节码-上 字节码文章分为上下两篇,上篇也就是本文主要讲述class文件存在的意义,以及其带来的益处.并分析其内在构成之一 ---字节码,而下篇则从指令集方面着手,讲解指 ...
- JVM(八):Java 对象模型
JVM(八):Java 对象模型 本文将学习对象是如何创建的,对象的内存布局,以及如何定位访问一个对象. 对象创建 当虚拟机碰到一个new指令时,首先检查指令参数能否在常量池中定位一个类的符号引用,并 ...
- JVM(十一):内存分配
JVM(十一):内存分配 在前面的章节中,我们花了大量的篇幅去介绍 JVM 内的内存布局.对象在内存中的状态.垃圾回收的算法和具体实现等.今天让我们探讨一下对象是如何分配内存的. 堆内存划分 前面说过 ...
- 深入理解JVM内幕:从基本结构到Java 7新特性[转]
英文原文:cubrid,编译:ImportNew - 朱伟杰 译文链接:http://www.importnew.com/1486.html [如需转载,请在正文中标注并保留原文链接.译文链接和译者等 ...
- Java并发指南5:JMM中的final关键字解析
本文转载自互联网,侵删 与前面介绍的锁和volatile相比较,对final域的读和写更像是普通的变量访问.对于final域,编译器和处理器要遵守两个重排序规则: 在构造函数内对一个final域的 ...
- JVM探秘:MAT分析内存溢出
本系列笔记主要基于<深入理解Java虚拟机:JVM高级特性与最佳实践 第2版>,是这本书的读书笔记. MAT是分析Java堆内存的一个工具,全称是 The Eclipse Memory A ...
随机推荐
- SQL Tuning Health-Check Script (SQLHC) (文档 ID 1366133.1)
Login to the database server and set the environment used by the Database Instance Download the &quo ...
- BZOJ 4238: 电压 DFS树
分类讨论一下奇环和偶环的情况. code: #include <bits/stdc++.h> #define N 200006 #define setIO(s) freopen(s&quo ...
- gulp常用插件之gulp-notify使用
更多gulp常用插件使用请访问:gulp常用插件汇总 gulp-notify这是一款gulp通知插件. 更多使用文档请点击访问gulp-notify工具官网. 安装 一键安装不多解释 npm inst ...
- Connections in Galaxy War ZOJ - 3261 离线操作+逆序并查集 并查集删边
#include<iostream> #include<cstring> #include<stdio.h> #include<map> #includ ...
- PP: Articial Intelligence—TheRevolution Hasn’t HappenedYet
From Michael I. Jordan As with many phrases that cross over from technical academic fields into gene ...
- afl-fuzz技术初探
afl-fuzz技术初探 转载请注明出处:http://www.cnblogs.com/WangAoBo/p/8280352.html 参考了: http://pwn4.fun/2017/09/21/ ...
- 记一个js toUpperCase函数 大小写特性
toUpperCase()是javascript中小写变大写的函数 "ı".toUpperCase() == 'I',"ſ".toUpperCase() == ...
- 常用命令 在linux下
1.拷贝某个目录及其下的所有的文件到另外一个目录 语法:cp -r <source directory name>/ <destination directory name>/ ...
- Treats for the Cows POJ - 3186 dp 区间dp
//dp[i][j]表示第i次从左边取,第j次从右边取的价值,所以我们可以得到状态方程 //dp[i][j]=max(dp[i-1][j]+(i+j)*a[i],dp[i][j-1]+(i+j)*a[ ...
- cdn第三方前端依赖架包共享地址
https://cdnjs.com/ 可在此网站查找你需要的稳定第三方前端依赖架包