多线程高级

一、计算机组成

 

  CPU:

  • ALU:运算单元,运算寄存器中的指令数据

     

  • Registers:寄存器,有几十个,CPU从内存中获得的指令,以及运行指令的所需要的数据读到寄存器中。寄存器是cpu内部的少量的速度很快的闪存,通常存储和访问计算过程的中间值提⾼计算机程序的运⾏速度

     

  • PC(program count):程序计数器,存储下一条操作指令的内存地址程序计数器是⼀个专⽤的寄存器,⽤于表明指令序列中 CPU 正在执⾏的位置,存的值为正在执⾏的指令的位置或者下⼀个将要被执⾏的指令的位置,具体实现依赖于特定的系统

     

  • Cahce:缓存。

  内存:程序启动,存储一条一条的程序操作指令和数据

 

 

  CPU和内存通信通过总线

    缓存行:cup在内存中读取数据,一次读取一个缓存行,64位系统中,一个缓存行是64bit/ 8个字节。

    每一个核都有自己一级二级缓存,所有核共享三级缓存。多块cpu共享内存。

二、Java内存模型

2.1、JVM内存区域

 

  • 方法区:类信息、常量、static 、JIT(即时编译)    (信息共享)

     

  • Java堆区:实例对象、GC(信息共享)   (OOM)

     

  • JVM stack:Java方法在运行的内存模型   (OOM)

     

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

     

  • Native method stack:  与JVM的native 

  JIT(即时编译):HotSpot中,JIT将热点代码编译成机器语言提高效率。

2.2、Java内存模型

  Java memory model(规范,抽象的模型)

  我们常说的JVM内存模式指的是JVM的内存分区;而Java内存模式是一种虚拟机规范。

  JMM和JVM的关系相当于MVC和SSM的关系,抽象和实现.

  Java虚拟机规范中定义了Java内存模型(Java Memory Model,JMM),用于屏蔽掉各种硬件和操作系统的内存访问差异, 以实现让Java程序在各种平台下都能达到一致的并发效果,JMM规范了Java虚拟机与计算机内存是如何协同工作的: 规定了一个线程如何和何时可以看到由其他线程修改过后的共享变量的值,以及在必须时如何同步的访问共享变量。

 

  1. 主内存:共享的信息
  2. 工作内存:私有信息,基本数据类型,直接分配到工作内存,引用的地址存放在工作内存,引用的对象存放在堆中
  3. 工作方式:
    1. 线程修改私有数据,直接在工作空间修改
    2. 线程修改共享数据,把数据复制到工作空间中去,在工作空间中修改,修改完成以后,刷新内存中的数据

三、对象在内存中的存储布局

 

  • markdown:对象头,8个字节,存储锁信息 ,GC信息,hashCode信息 

     

  • class pointer:对象头,类型指针,指向堆中对象Class,64位的JVM,指针的长度就是8个字节,但是由于虚拟机默认开启指针压缩,所以是4个字节。

     

  • instance data:由于没有属性,0字节

     

  • padding:补齐,当对象的整体字节数不能被8整除时,补齐,提高效率

3.1、使用JOL

  JOL :对象内存布局

<dependencies>
<!-- https://mvnrepository.com/artifact/org.openjdk.jol/jol-core -->
            <dependency>
                <groupId>org.openjdk.jol</groupId>
                <artifactId>jol-core</artifactId>
                <version>0.9</version>
            </dependency>
</dependencies>
public static void main(String[] args) {
        Object o = new Object();
        System.out.println(ClassLayout.parseInstance(o).toPrintable());
}

 

 

   运行:java -XX:PrintCommandLineFlags –version

C:\Users\jdy>java -XX:+PrintCommandLineFlags -version
-XX:InitialHeapSize=132533888 -XX:MaxHeapSize=2120542208 -XX:+PrintCommandLineFlags 
-XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC java version "1.8.0_144" Java(TM) SE Runtime Environment (build 1.8.0_000000 144-b01) Java HotSpot(TM) 64-Bit Server VM (build 25.144-b01, mixed mode)

 

  • UseCompressedClassPointers:压缩指针,默认打开 原来class pointer是8个字节,经过指针压缩后是4个字节 Java虚拟是64位,则指令默认是64位,8个字节。
  • UseCompressedOops:普通对象指针(person 的name )压缩后也是4个字节。

3.2、markword

  markword作用: 存储锁信息 ,GC信息,hashCode信息

public static void main(String[] args) {
        Person person = new Person();
        System.out.println(ClassLayout.parseInstance(person).toPrintable());
        synchronized (person){
            System.out.println(ClassLayout.parseInstance(person).toPrintable());
        }
}

 

 

四、CAS

4.1、CAS / 自旋 / 自旋锁 / 无锁 

  Compare And Swap (Compare And Exchange)

 

 

 

  因为经常配合循环操作,直到完成为止,所以泛指一类操作。cas(v, a, b) ,变量v,期待值a, 修改值b

   1.先把要操作的的值读取E,

           2.将读到的值将过操作后等到V.

           3.再去读去要操作的值读入到N

           4.比较E和N E=N 将新值V写如内存,如果E!=N,则一直重1-4的过程

 

   ABA问题,你的女朋友在离开你的这段儿时间经历了别的人,自旋就是你空转等待,一直等到她接纳你为止。解决办法(版本号 AtomicStampedReference),基础类型简单值不需要版本号。

4.2、CAS应用

/**
 * AtomicXXX类底层的CAS操作都是通过Unsafe类
 * Unsafe类中有很多被native修饰的compareAndSwapXXX方法。
 */
AtomicInteger at = new AtomicInteger();
at.compareAndSet(,1);

 

  Unsafe在hotspot(虚拟机)内的源码:CAS的最终实现是cmpxchg指令,如果是多CPU,指令是lock cmpxchg

  cmpxchg 指令不是原子操作,加Lock是在当前CPU在操作当前内存时,其他cpu不能操作当前内存,lock指令实际上时锁一个北桥信号。

 

  

 

posted @ 2021-04-15 23:38  jingdy  阅读(120)  评论(0编辑  收藏  举报