技术专题JVM

深入理解JVM 系列(一)JVM运行机制 JVM 内存模型(v

2017-09-05  本文已影响126人  Gxgeek

为了 接下去 更好理解 JAVA 并发,多线程 JUC 包的原理 特此写下前置学习文章 深入学习 java 虚拟机

本文目录

一、java 程序 启动流程

启动流程

java 命令开始
寻找 配置文件 定位需要的 .dll
.ddl 初始化 JVM 虚拟机
获得 native 接口
找到main 方法运行

二、JVM结构(运行时数据区)

JVM结构(运行时数据区)

- 二.一、线程私有的区域

1.程序计数器(PC寄存器)

2.栈(VM Stack)

mark

mark

mark
每个线程包含一个栈区,栈中只保存基础数据类型和自定义对象的引用(不是对象),对象都存放在堆区中
每个栈中的数据(原始类型和对象引用)都是私有的,其他栈不能访问。
栈分为3个部分:基本类型变量区、执行环境上下文、操作指令区(存放操作指令)。

3.本地方法栈(Native Method Stack)

-二.二、线程共享区域

Method Area(方法区) 方法区是堆的逻辑部分。

(这个只是JVM 中的 一个规范设计 每个厂商可能实现不同 本文会尽可能的 使用JDK1.8 的HotSpot 作为讲解)
在 HotSpot中 我们有了新的东西 就是 Metaspace(元空间) 是对 JVM规范中方法区的实现
元空间并不在虚拟机中,而是使用本地内存。因此,默认情况下,元空间的大小仅受本地内存限制,但可以通过设置参数来指定元空间的大小。所有线程共享的。

JAVA 堆 (Heap )全局共享

直接内存

三、java 的内存模型

对于普通变量,一个线程中更新的值,不能马上反应在其他变量中 如果需要在其他线程中立即可见,需要使用 volatile 关键字
mark

3.1、多线程操作变量模型

mark

3.2、关键字volatile

volatile 不能代替锁
一般认为volatile 比锁性能好(不绝对)
选择使用volatile的条件是:
语义是否满足应用
因为多线程操作和volatile两个意思

关键字volatile 效果
public class VolatileStopThread extends Thread{
    private volatile boolean stop = false;
    public void stopMe(){
    stop=true;
    }
    
    public void run(){
    int i=0;
    while(!stop){
    i++;
                 }
               System.out.println("Stop thread");
    }
    
    public static void main(String args[]) throws InterruptedException{
    VolatileStopThread t=new VolatileStopThread();
    t.start();
    Thread.sleep(1000);
    t.stopMe();
    Thread.sleep(1000);
    }
}
//根本停不下来
// 类似效果
@Slf4j
public class VolatileExample extends Thread{
    //设置类静态变量,各线程访问这同一共享变量
    private  static  boolean flag = false;
    //无限循环,等待flag变为true时才跳出循环
    public void run() {
        while (!flag){
        };
        log.info("停止了");
    }

    public static void main(String[] args) throws Exception {
        new VolatileExample().start();
        //sleep的目的是等待线程启动完毕,也就是说进入run的无限循环体了
        Thread.sleep(100);
        flag = true;
    }
}

synchronized (unlock之前,写变量值回主存)

final(一旦初始化完成,其他线程就可见)

3.3 指令重拍

指令重拍就是编译器按照理解的优化代码
可能会不按照代码顺序来 不会进行对象依赖的重拍
会重拍对象之间不依赖的进行重拍
最后 保证 整个线程的语义不发生改变

    写后读 a = 1;b = a;    写一个变量之后,再读这个位置。
    写后写 a = 1;a = 2;    写一个变量之后,再写这个变量。
    读后写 a = b;b = 1;    读一个变量之后,再写这个变量。
    以上语句不可重排
mark

例子 -----> 正确方法多线程 指令重拍的错 synchronized 锁住对象


mark
3.3.1 指令重排的基本原则

编译运行(JIT)

本文参考文献

我的公众号

微信公众号
上一篇下一篇

猜你喜欢

热点阅读