并发学习-1

一、基本概念

  • 程序:代码,为了完成某一任务的,代码序列 静态
  • 进程:程序完成某一任务的一次运行 动态
  • 线程:一个进程由多个线程组成

二、JVM与线程

  JVM什么时候启动? 答:类被调用  JVM线程包含其他线程(main)

三、JVM的内存区域

  方法区,堆、程序计数器、本地方法栈,java栈 等区域。详情请看图1-1

  • 方法区:类信息、常量、static、JIT(及时编译器)(共享区域)
    1. 类信息:由classLoader(类加载器)
    2. 常量:成员变量
    3. static变量:静态变量
    4. JIT:即时编译
  • 堆:实例对象、GC(共享区域)OOM指的是存在内存溢出的风险
  • java栈:运行时的内存模型 图1-2   OOM指的是存在内存溢出的风险
  • 程序计数器(PC):java线程的私有数据,这个数据就是记录执行下一指令的地址
  • 本地方法栈:与虚拟机的native有关系

四、java的内存模型 JMM(规范,抽象模型) 图1-3

  • 主内存:共享数据,引用类型的对象放在主内存
  • 工作内存:私有数据,线程就是在工作内存中存在的,基本数据类型直接存在工作内存,引用的类型的的地址放在工作内存。
  • 工作方法:
    1. A线程如果要修改私有数据,会在A线程工作空间找,没找到将会去主内存中找到并复制到工作空间,并进行修改。
    2. B线程如果要修改共享数据,同理上面,但是区别于复制到工作空间后修改完毕会再刷新(赋给)主内存。为什么要这样设计?为了确保信息的保密性,个人理解相当于你和别人借钱要买某保险,你一定是先将钱借到手,再去买,而不是带着业务员去借钱对象的家里面买保险

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

  • 硬件内存架构  图1-4 CPU只的是CPU运行区(处理器内存,并不是4核 2核CPU概念,指的是CPU分配时间片)
    1. CPU缓存一致性:内存中存在变量A=1,CPU1获取A的值之后要进行修改A=2,此时CPU2获取变量A有可能是1也可能是2.因为CPU修改完毕后会通过cache(缓存)刷新到内存中。如果还没有保存到内存中那么CPU2将获取的A=1,反之A=2.。此时会出现并发不同步(不安全)
    2. 解决的问题
      • 总线加锁:此种方法很影响CPU的吞吐量,虽然能保证数据的一致性,但是牺牲了大量的时间,类似于java中的方法使用sysnchronize,同一时间只能一个CPU用。
      • cache缓存一致性协议(Intel协议,MESI协议):CPU从cache获取变量到寄存器中修改完毕后,会将cache中的变量设置一个状态 cache Line为无效类似于state=0,其他CPU如果检测到cache Line为0时则直接从内存中获取变量的value,防止其他CPU从cache读取脏数据
  • 线程与硬件处理器 图1-5    进程>线程>操作系统OS>CPU
  • java内存模型与硬件内存架构的关系  图1-6
    1. 图中可以看到是JMM(虚拟机数据模型)与CUP内存架构是交叉关系,所以会造成数据不一致性
  • java内存模型的必要性
  • java内存模型的作用:规范内存数据(主内存)与工作空间(工作内存)的交互

六、并发编程的三个重要特征

  • 原子性:不可分割的,同生共死。
  • 可见性:一个线程只能读写自己的工作空间(工作内存)的cache
  • 有序性:程序中的顺序不一定就是执行顺序,
    1. 编译的时候会重排,
    2. 指令也会重排,
    3. 为了提高效率
    4. 例子:int a=1;int b=2;int c=0; c=a+b; int d=0; 因为变量c比较复杂,所以效率慢,排序后先执行d=0;再去执行c=a+b;
      • 单线程重排规则(编译优化):as-if-seria规则,重排后不影响执行结果
      • 多线程重排规则(指令优化):happens-before规则,程序次序原则(程序的结果不能变化),锁定原则(后一次加锁必须等前一次解锁),Volatile原则(霸道原则),传递原则(A语句再B语句前执行,最后C执行,得出的结论是A必须在C语句前执行。A--B--C    A--C)。

七、JMM(java内存模型)三大特性的保证

  • JVM的原子性
    1. int x = 10; 基础类型是存在工作空间,所以写入的时候就是存在原子性。如果是私有数据具有原子性,如果是共享数据则没有原子性。先读后写则不存在原子性
    2. int y = x;没有原子性。原因:把数据x读取到工作空间(原子性) 把x的值写到y(原子性)但是读写后则不存在原子性
    3. int i++;没有原子性。原因:读i到工作空间,然后写入i+1,内存刷新结果,单个执行都具有原子性,但是放到一起不具备原子性。
    4. int Z=z+1;没有原子性,原因:先将z读到工作空间,然后计算z+1,赋值给Z,内存刷新结果。
    • 结论:多个原子性的操作合并到一起就没有原子性。怎么保证原子性呢?
    • 保证方式:
    1. Synchronized
    2. JUC Lock的lock加锁
  • JMM的可见性
    1. 工作空间修改了变量后,刷新给内存后,怎么保证其他工作空间队内存的变量的可见性
    • 保证可见性方式:
      1. 使用Volatile:再JMM模型上实现MESI协议。
      2. Sysnchronized:加锁
      3. JUC LOCK的lock加锁
  • JMM的有序性
    • 保证方式:
    1. Volatile
    2. Synchronized

       Happens-before规则

八、总结

  • JVM内存区域和JMM(抽象java内存模型)的关系
  • JMM和硬件的关系
  • JMM和并发编程三个重要特征  *(有序性 as-if-seria和happens-before)

欢迎大家来提问,如果有不理解的可以再评论区提出,我会定时解惑。

同舟共济,新海同航

图1-1                                                                                    图1-2                      图1-3

 

          图1-4                图1-5                图1-6

                                    

java中的start如何调用run方法?

1、模板模式、线程是对应操作系统的线程,一一对应的。因为需要将你想做的逻辑让操作系统去执行。

start---start0---native---pthread_create(java_start){

}

void{

java_start jni反射调用java run

}

原文地址:https://www.cnblogs.com/gnwzj/p/10541855.html