博客
关于我
深入理解JVM(一)JVM概述、类的声明周期、JVM整体架构、JMM、volatile
阅读量:390 次
发布时间:2019-03-05

本文共 2370 字,大约阅读时间需要 7 分钟。

JVM与Java环境的深入探讨

JVM(Java Virtual Machine),即Java虚拟机,是Java编程语言运行的核心引擎。要深入理解JVM,我们首先需要明确其与JDK(Java Development Kit)的关系。JDK不仅包含JVM,还包含了一系列屏蔽操作系统差异的组件,这些组件的作用是将Java程序在不同操作系统上统一运行,实现了Java的跨平台特性。

JVM的工作原理

从程序的编译与执行过程来看,JVM主要负责以下几个步骤:

  • 类的加载:当JVM执行一个Java程序时,它首先需要加载目标类。JVM会利用类装载器(class loader)来查找并加载类文件。如果类文件不存在,JVM会抛出错误。

  • 类的链接:加载完成后,JVM需要对类进行链接。链接过程包括检验、准备和解析三个阶段:

    • 检验:验证类文件是否符合Java语义规范。
    • 准备:为静态变量分配内存并赋予初始值,建立方法表等。
    • 解析:处理符号引用,将其转换为直接引用,确保类之间的依赖关系正确。
  • 类的初始化:在类被使用之前,JVM会执行类的初始化操作。初始化包括执行构造器(static initializer)和静态变量的初始化,确保类的内部状态一致。

  • 类的使用:完成初始化后,JVM会执行类的主方法(如main方法),驱动程序的执行。

  • 类的卸载:当类不再使用时,JVM会将其卸载出运行时数据区域,释放内存资源。

  • JVM内存模型

    JVM内存模型是Java程序运行的核心机制,它定义了内存的使用方式和区域划分。JVM内存主要由以下几个部分组成:

    • 堆(Heap):用于存储对象实例,占用大部分内存空间。
    • 方法区(Method Area):存储类信息、常量、静态变量等数据。
    • 本地方法栈(Native Method Stack):用于存储本地方法(如JNI调用)的相关信息。
    • 程序计数器(Program Counter):跟踪当前线程执行的位置。
    • 操作数栈(Operand Stack):存储操作数,用于执行操作。
    • 返回值栈(Return Value Stack):存储方法调用的返回值。

    线程间的内存通信

    在JVM中,线程间的内存操作需要通过主内存进行。线程间的通信遵循以下原则:

  • 线程B的工作内存中的共享变量必须首先刷新到主内存。
  • 线程A从主内存中读取线程B更新的共享变量。
  • JVM规定线程间的内存操作必须通过以下8个原子操作:

  • Lock:对主内存变量进行锁定。
  • Read:将主内存中的数据读入工作内存。
  • Load:将读取的数据拷贝到工作内存的副本中。
  • Use:将工作内存的数据副本进行使用。
  • Assign:将工作内存中的变量副本进行赋值。
  • Store:将工作内存中的变量副本刷新到主内存。
  • Write:将变量副本存入主内存。
  • Unlock:解除对主内存的锁定。
  • volatile关键字

    为了防止JVM对长整型和双整型数据类型的非原子性操作进行重排序优化,JVM引入了volatile关键字。volatile的作用包括:

  • 防止重排序:阻止JVM对volatile变量的读写操作进行重排序优化。
  • 提供线程可见性:确保所有线程立即可见volatile变量的最新值。
  • 防止指令重排序:通过插入屏障(StoreLoad、LoadLoad等)确保读写操作的原子性。
  • 需要注意的是,volatile并不能保证原子性操作。要实现原子性操作,建议使用java.util.concurrent.atomic包中的类,例如AtomicInteger、AtomicLong等。

    原子性与非原子性

    在Java中,除了一些特定的原子操作之外,大多数操作都是非原子性的。例如,int num = 10会被拆分为两个步骤:int num = 0;num = 10。这种拆分可能导致线程安全问题,特别是在多线程环境下。

    一个经典的单例模式问题

    以下是一个常见的单例模式问题:

    private static Singleton instance = null;private Singleton() {}public static Singleton getInstance() {    if (instance == null) {        synchronized(Singleton.class) {            if (instance == null) {                instance = new Singleton();            }        }    }    return instance;}

    这个代码在多线程环境下可能会出现问题,因为instance = new Singleton()不是一个原子操作。为了确保线程安全,可以在instance字段上使用volatile修饰:

    private static volatile Singleton instance = null;

    JVM的内存屏障

    volatile通过插入内存屏障来防止重排序问题:

    • StoreLoad屏障:在volatile写操作后插入。
    • LoadLoad屏障:在volatile读操作前插入。
    • StoreStore屏障:在volatile写操作前插入。
    • LoadStore屏障:在volatile读操作后插入。

    这些屏障确保了volatile变量的读写操作不会被重排序,从而保证了线程安全。

    总结

    通过以上对JVM的深入探讨,我们可以清晰地了解JVM的工作原理、内存模型以及线程间的通信机制。JVM不仅是Java程序运行的核心引擎,也是Java跨平台特性的关键实现。理解JVM的内存模型和线程调度机制,对于编写高效、线程安全的Java程序至关重要。

    转载地址:http://cbpzz.baihongyu.com/

    你可能感兴趣的文章
    [网站公告]又拍云API故障造成图片无法上传(已恢复)
    查看>>
    上周热点回顾(12.16-12.22)
    查看>>
    云计算之路-阿里云上:对“黑色30秒”问题的猜想
    查看>>
    云计算之路-阿里云上:“黑色30秒”走了,“黑色1秒”来了,真相也许大白了
    查看>>
    云计算之路-阿里云上:奇怪的CPU 100%问题
    查看>>
    云计算之路-阿里云上:2014年6月12日12点IIS请求到达量突降
    查看>>
    上周热点回顾(6.9-6.15)
    查看>>
    上周热点回顾(6.16-6.22)
    查看>>
    上周热点回顾(6.23-6.29)
    查看>>
    上周热点回顾(10.20-10.26)
    查看>>
    上周热点回顾(2.16-2.22)
    查看>>
    上周热点回顾(3.2-3.8)
    查看>>
    [网站公告]3月10日23:00-4:00阿里云SLB升级,会有4-8次连接闪断
    查看>>
    .NET跨平台之旅:借助ASP.NET 5 Beta5的新特性显示CLR与操作系统信息
    查看>>
    上周热点回顾(7.27-8.2)
    查看>>
    上周热点回顾(9.28-10.4)
    查看>>
    上周热点回顾(3.28-4.3)
    查看>>
    上周热点回顾(5.2-5.8)
    查看>>
    上周热点回顾(5.9-5.15)
    查看>>
    上周热点回顾(8.8-8.14)
    查看>>