并发编程1-JMM

解决的问题

线程与jvm

java 内存区域和 java 内存模型的区别

硬件内存架构与java内存模型

java 内存模型对并发的保证


基本概念

1. 程序:代码,完成某一个任务或者业务的代码序列;比如qq
2. 进程:程序在某些数据上的一次运行 ; 比如 我调用一个接口  这就是一个进程
3. 线程:一个进程包含多个线程,占有资源的独立单元

jvm 与 线程

jvm 什么时候启动 --》 类被调用的时候; 会有jvm 线程 执行到main 方法的时候 会创建 main进程,线程是存在于jvm 中

jvm 的内存区域

1.方法区中都是共享的信息

方法区:主要放置:类的信息【由classLoad进行加载的】;常量;staic;JIT  

2.Java堆区也是共享的信息;会发生oom

堆区:存放的实例变量,可见 垃圾处理GC 会常常光顾这片区域;{每个线程的栈都是该线程私有
的,堆则是所有线程共享的。当我们new一个对象时,该对象就被分配到了堆中。但是堆,并不是
一个简单的概念,堆区又划分了很多区域,为什么堆划分成这么多区域,这是为了JVM的内存垃圾
收集,似乎越扯越远了,扯到垃圾收集了,现在的jvm的gc都是按代收集,堆区大致被分为三大
块:新生代,旧生代,持久代(虚拟的);新生代又分为eden区,s0区,s1区。新建一个对象时
,基本小的对象,生命周期短的对象都会放在新生代的eden区中,eden区满时,有一个小范围的
gc(minor gc),整个新生代满时,会有一个大范围的gc(major gc),将新生代里的部分对象转
到旧生代里。原文链接:https://blog.csdn.net/u013851082/article/details/70314778/}

3.虚拟机栈 会发生OOM

虚拟机栈:java方法运行的内存模型;每一个java方法都有唯一的栈帧对应;
不能实现数据共享;而且每一个栈帧的容量是有限的!在方法内 死循环会造成 OOM!
摘自:
{线程的每个方法被执行的时候,都会同时创建一个帧(Frame)用于存储本地变量表、操作栈、动
态链接、方法出入口等信息。每一个方法的调用至完成,就意味着一个帧在VM栈中的入栈至出栈的
过程。如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常;如果VM
栈可以动态扩展(VM Spec中允许固定长度的VM栈),当扩展时无法申请到足够内存则抛出
OutOfMemoryError异常。
原文链接:https://blog.csdn.net/u013851082/article/details/70314778/}
我们可以对整个虚拟机栈设置 大小;但是 栈帧的大小 有jvm自己根据 变量数等等来 分配 不可控;

4.pc 程序计数器,每一个Java线程都有一个程序计数器来用于保存程序执行到当前方法的哪一个指令

java 线程的私有数据,这个数据就是执行下一条指令的地址

5.native method statck JVM 本地方法栈

java 内存模型

  1. 共用内存:共享信息
  2. 工作空间:私有信息,每一个线程都有自己的工作空间,存放自己的私有信息,比如…;保证数据的不可见性;基本的数据类型,直接分配到工作内存中;引用类型 的 地址 也存放在工作空间中,引用的对象存放在 堆中;
  3. 工作模式:
    1. A 线程修改私有数据,直接在工作空间修改
    2. B 线程修改共享数据,先读到工作空间进行修改,修改完成后,刷新内存中的数据
  4. jvm 内存区域 就是 根据 JMM 来设计的 JMM 就是一种模型 思想 ;看不见的东西;相当于一种规范;这两个可以 由 springmvc–mvc设计思想,用这种思想影响操作; 这里的工作空间 可以看成 vm stack 和 pc ;他的作用就是规范内存数据和工作空间数据的交互

硬件内存架构与java 内存模型

java 内存模型为什么可以扯到硬件呢?因为 jvm 是在 内存中运行的;抛开这个不谈,现在的计算器
,cpu在计算的时候,原始的数据来自内存 在计算过程中,有些数据可能被频繁读取,
这些数据被存储在寄存器 和高速缓存中,当线程计算完后,这些缓存的数据在适当的时候应该写回内存。
当个多个线程同时读写某个内存数据时,就会产生多线程并发问题,
涉及到三个特 性:原子性,有序性,可见性。
下图展示硬件的内存架构:

与上面的java内存模型是不是非常相像;要看他们之间共同点,java内存模型中的共用内存,就是硬件的内存;线程的工作空间,可以是寄存器也可以是缓存 或者 内存;因为线程的数据会来自缓存和内存以及寄存器中;

在硬件的层面上如何进行加锁呢保证线程安全

1.总线加锁,相当于串行,安全但是降低了cpu的吞吐量
2.缓存上的一致性协议MESI:当CPU在寄存器中操作数据,如果该数据时共享变量,数据在修改的时候,CACHE LINE 置为无效,其他的CPU 就从内存中读取数据

Java线程与硬件处理器的关系

任务过来之后,会从线程池获取一个线程,线程转化为一个内核线程,从而操作 硬件;

并发编程的三个重要特性

1.原子性:不可分割比如,x= 1;x+=1 不是原子性的 因为涉及到多个原子性的操作;
2.可见性:线程只能操作自己工作空间的数据
3.有序性:程序的顺序不一定就是cpu 执行的顺序;一行代码在cpu看来就是多条指令,cpu 为了优化程序执行;会进行编译时指令重排序,目的是提高效率
重排序需要满足两个规则:
1. as-if-seria原则 在单线程中重排序不影响程序运行的结果
2. happens-before原则:必须等到锁释放,才能访问目标资源;volatile修饰的变量,这一行所在的代码不会重排序。

JMM如何保证原子性

  1. 什么是原子性:
  2. X=10 写 —> 如果是私有数据具有原子性,如果是共享数据没原子性(读写)
    2. Y=x 没有原子性
    1. 把数据X读到工作空间(原子性)
    2. 把X的值写到Y(原子性)
  3. I++ 没有原子性
    1. 读i到工作空间
    2. +1;
    3. 刷新结果到内存
  4. Z=z+1 没有原子性
    1. 读z到工作空间
    2. +1;
    3. 刷新结果到内存


如何保证原子性呢?
1. synchronized
2. juc

JMM 与 可见性

什么是可见性:
线程修改共享数据,其他线程能够感知到!!!在硬件层面上 有一个 MESI协议;
1.在JMM模型上同样也有类似实现了MESI协议也就是 volatile;被volatile修饰的变量,A线程读取后,B线程要在内存中获取;但是如果A线程没有刷新到 内存中;B线程仍然会读取到 旧值;
2.synchronized
3.JUC

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值