暑期集训第七天

前言

今天的知识点有点涉及自己自习的不扎实的地方了(内存这东西真是学了就bu忘shi),所以今天在博客内总结一下。
首先不得不提,JVM内存模型和Java内存模型(JMM)是两个东西,JVM内存模型是与JVM的内部存储结构相关,而Java内存模型是与多线程编程相关。

java内存模型(JMM)

附上B站教学视频
这个老师讲的超级清楚

我们来看这个图(图壹),我们根据这个图来讲
在这里插入图片描述
这两个线程,共用一个变量intFlag
由于这个变量是公用的,是不是意味着一个线程改变它以后,另外一个线程就能感知到并作出相应改变呢?
这就要我们从JMM模型来分析了
首先我们要了解一下计算机的大致内存模型


计算机大致内存模型

在这里插入图片描述
左侧是最原始的内存模型,由于CPU的运算速度符合摩尔公式,程指数倍递增,而RAM主存速度是不会变的,这就导致了两者不匹配,RAM跟不上CPU,所以科学家就设计出了如右图的模型,即加入了CPU缓存(其实在缓存和RAM中间还有总线),使得两者匹配


好,在我们看过计算机大致的存储模型以后,我们再来讲一下Java虚拟机,也就是JVM。众所周知Java是一门跨平台的语言,即一处编译处处执行,依靠的就是Java虚拟机,Java虚拟机的实现,有一部分是模拟操作系统来实现的,现阶段我们可以近似看成如图壹的那样,也拥有一个主存一个总线,一个CPU(核),核内有工作内存(CPU缓存)和线程内容。
其中主存和CPU之间有这些操作
在这里插入图片描述
结合图壹,我们可以看出,一个线程在执行时,会先把这个量read进去,在自己的工作内存中复制一份,之后再use这个复制品,因此,一般的变量,在一个线程的修改,是不会影响另一个线程的,因为两者实际use的不是一个东西,他们use的都只是自己的工作内存中的复制品。

有序性、原子性、可见性

有序性:在线程内部的两行代码的实际执行顺序和代码在Java文件中的逻辑顺序不一致,代码指令并不是严格按照代码语句顺序执行的
原子性:指一系列的操作,要么全部执行成功,要么全部不执行,不会出现执行一半的情况,是不可分的
可见性:指是当一个线程修改了某个共享变量的值,其他线程是否能够马上得知这个修改的值


那么我们要如何保证这三个性质呢?
这宫里给出两个关键词


volatile

这个关键词保证了可见性,但是不保证原子性,什么意思呢
虽然由于多核CPU普及,最原始的lock、unlock被淘汰了,取而代之的是MESI缓存一致性协议,但是我们理解的时候还是可以用上lock和unlock,比如我们两个线程,一个在i++一个在i–,最终执行结束之后的i是什么呢?结果有三种,0,-1,1。因为两个线程执行的时候,是不能保证谁先执行完的,而根据MESI,先执行完的线程,write了主内存的i,并且在它write时,对i进行了lock,然后,后执行完的线程的嗅探机制检测到主线内的lock并使得该线程清空了它的工作内存里的i,使得自加或者自减操作最终只生效了一次,当然也可能第一个执行完,并且write后第二个线程才第一次将共享变量read并进行后续操作,这样就会i=0,即返回逻辑上的结果。

synchronized

synchronized语义表示锁在同一时刻只能由一个线程进行获取,当锁被占用后,其他线程只能等待。这样就保证了原子性,还是那个例子,同样的底层,只不过保证了只会执行i=0,的那种具体实现。


以上两者都能保证有序性,但有序性是相对线程内部的,即另外的线程看此线程,就可能是无序的。

JVM相关知识点与对象生命周期

JVM是什么

JVM(java virtual machine)也就是java虚拟机,是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能模拟来实现的。Java虚拟机有自己完善的硬件架构,如处理器、堆栈、寄存器等,还具有相应的指令系统。
JVM有方法区、java堆、java栈(虚拟机栈)、本地方法栈、PC程序计数器。
程序计数器:
程序计数器是一块很小的内存空间,用于记录下一条要运行的指令。每个线程都需要一个程序计数器,各个线程之中的计数器相互独立,是线程中私有的内存空间。
** java虚拟机栈:**
Java虚拟机栈也是线程私有的内存空间,它和java线程同一时间创建,包括当前方法的所有本地变量信息栈中存放方法中的局部变量,方法的运行一定要在栈中,要先把方法给压入栈。等到超出作用域之后就消失(用完就丢)
本地方法栈:
本地方法栈和java虚拟机栈的功能相似,java虚拟机栈用于管理Java函数的调用,而本地方法栈用于管理本地方法的调用,但不是由Java实现的,而是由C实现的
java堆:
为所有创建的对象和数组分配内存空间,被JVM中所有的线程共享,也就是凡是new出来的东西都要放在堆当中,堆内存当中的所有东西都会有地址值,通过引用可以获得其地址值
方法区:
存放.class的相关信息,也就是编译后的文件存放在此,这里有方法的具体实现
在这里插入图片描述
那么什么时候会创建新的对象,即在堆里面写入数据,而不是直接在容量池里创建呢?

Character 类:缓存 0~127 的字符,其它需要新创建。
Byte,Short,Integer,Long 类:缓存 -128~127 的对象,其它值需要重新创建。
Float,Double 类:没有缓存,直接创建。
Boolean 类:缓存 true 和 false 两个对象,直接赋值即可。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值