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. 【1】Logistic回归

    Logistic回归  在Logistic回归中,损失函数L定义为 成本函数 J  损失函数是单个训练样本的误差,而成本函数是所有训练样本误差的平均值. 之所以选择这个损失函数,是因为该损失函数L与w ...

  2. cf 989C

    构造一个网格图使得四种类型的联通分量分别有a,b,c,d 看图就知道应该如何去构造了 int gird[maxn][maxn]; int main(){ int a[4]; for(int i=0;i ...

  3. ubuntu set up 6 - NTFS Mount

    1. NTFS Mounted as read-only https://askubuntu.com/questions/1138076/ubuntu-18-04-cant-write-on-ntfs ...

  4. php 字符串常用函数

    数组.字符串和数据库是我们函数里面最.最.最常用的三类函数. 当然PHP的字符串函数也有很多.我们最常使用的两个系列的字符串: 1.单字节字符串处理函数 2.多字节字符串处理函数 3.字符串编码转换函 ...

  5. Centos下安装Oracle12c

    总结一次安装oracle的折腾血泪史环境准备 centos7 虚拟机VMware Workstation Pro14 IP:192.168.245.128(根据实际情况) 4G物理内存,8G虚拟内存, ...

  6. Java_Day4(上)

    Java learning_Day3(上) 本人学习视频用的是马士兵的,也在这里献上 <链接:https://pan.baidu.com/s/1qKNGJNh0GgvlJnitTJGqgA> ...

  7. XSS漏洞的poc与exp

    poc <script>alert('xss')</script>  最简单常用的poc <a href='' onclick=alert('xss')>type& ...

  8. Tickets HDU - 1260 简单dp

    #include<iostream> using namespace std; const int N=1e5; int T,n; int a[N],b[N]; int dp[N]; in ...

  9. c#从前台界面找后台方法

    比如你新接触一个项目  项目别人已经写的差不多了  你对项目一无所知,别人安排给你活  怎么最快速度找到你要干的活对应的东西 以谷歌浏览器为例 一个项目你要修改  库存信息列表 右键检查或者F12 找 ...

  10. @RendSection{"scripts",require:false}的作用

    MVC视图中,Javascripts代码被放于下面的Razor代码中(@section Scripts{}). 好处:在视图进行JavaScript编程时,是一个很好的实践,在共享视图(_Layout ...