详解Java对象结构与对象锁的升级

详解Java对象结构与对象锁的升级

Java对象结构

Java对象在内存中的实际存储由三部分组成:对象头、实例数据和对齐填充。

对象头

对象头是Java对象的一部分,用于存储对象自己的运行时数据,包括以下内容:

  • Mark Word: 用来锁定对象、记录对象哈希值、记录对象所属的分代年龄等信息。
  • Class: 指向对象的Class对象。

在Java 8中,对象头的大小为12字节。

实例数据

实例数据存储对象的实例变量,实例数据相对于对象头的大小是不定的,因为它取决于对象的实例变量数量和类型。

对齐填充

为了对齐对象在内存中的地址,可能需要在实例数据末尾补充填充数据,使得对象的大小是8字节的整数倍。在Java 8中,所需的填充量最多为7个字节。

对象锁的升级

Java中的对象锁分为偏向锁、轻量级锁和重量级锁。

偏向锁

偏向锁是一种针对加锁频繁性不高的场景的优化,偏向锁的意思是,偏向某个线程,这个线程在获取锁之后,当再次进入同步块时,因为上一次已经获取过锁了,所以可以直接获得锁,而不需要重新去竞争。

下面是一个偏向锁示例:

public class BiasedLockDemo {
    private static final int COUNT = 10_000_000;
    public static void main(String[] args) throws InterruptedException {
        Object obj = new Object();
        long start = System.currentTimeMillis();
        for (int i = 0; i < COUNT; i++) {
            synchronized (obj) {
                // do nothing
            }
        }
        System.out.println("Synchronized cost : " + (System.currentTimeMillis() - start) + "ms");

        Thread.sleep(10000);

        start = System.currentTimeMillis();
        for (int i = 0; i < COUNT; i++) {
            synchronized (obj) {
                // do nothing
            }
        }
        System.out.println("Synchronized cost : " + (System.currentTimeMillis() - start) + "ms");
    }
}

在上面的示例中,第一次进入同步块时,JVM会偏向此线程,并记录对象的Mark Word为偏向锁模式。因为只有一个线程,所以不会有竞争,性能最优。第二次进入同步块时,因为对象已经记录了偏向线程,所以直接判断Mark Word是否指向该线程,如果是,则直接获取锁,不再竞争锁。

轻量级锁

如果一个线程没有成功获取偏向锁,或者偏向锁被取消了,那么它就会尝试轻量级锁来获取锁。轻量级锁使用CAS操作,将对象头中的Mark Word复制到线程的栈帧中,表示当前线程已经获得了这个锁。如果CAS操作成功,则当前线程成功获得锁,继续执行同步块。如果CAS操作失败,表示有竞争,此时当前线程会自旋一段时间,等待其他线程释放锁。

下面是一个轻量级锁示例:

public class LightweightLockDemo {
    private static final int COUNT = 10_000_000;
    public static void main(String[] args) throws InterruptedException {
        Object obj = new Object();
        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < COUNT; i++) {
                synchronized (obj) {
                    // do nothing
                }
            }
        }, "thread-1");
        Thread thread2 = new Thread(() -> {
            for (int i = 0; i < COUNT; i++) {
                synchronized (obj) {
                    // do nothing
                }
            }
        }, "thread-2");

        long start = System.currentTimeMillis();
        thread1.start();
        thread2.start();
        thread1.join();
        thread2.join();
        System.out.println("Synchronized cost : " + (System.currentTimeMillis() - start) + "ms");
    }
}

在上面的示例中,两个线程同时竞争同一个对象锁,因此会导致竞争,此时第二个线程会自旋等待第一个线程释放锁。

重量级锁

如果轻量级锁获取失败,则会进入重量级锁模式。此时线程会进入操作系统的内核态,进入阻塞状态,等待其他线程释放锁。

下面是一个重量级锁示例:

public class HeavyweightLockDemo {
    private static final int COUNT = 10_000_000;
    public static void main(String[] args) {
        Object obj = new Object();
        synchronized (obj) {
            try {
                Thread.sleep(100000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

在上面的示例中,线程进入同步块后,会一直等待100秒,此时其他线程无法获取锁,只能等待该线程释放锁,因此此时已经进入重量级锁模式。

总结

Java对象在内存中的实际存储由三部分组成:对象头、实例数据和对齐填充。对象锁分为偏向锁、轻量级锁和重量级锁。在多线程并发环境下,不同的锁模式可以优化性能,提升程序的吞吐量。

以上就是Java对象结构与对象锁升级的详细攻略,希望能够对你有所帮助。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:详解Java对象结构与对象锁的升级 - Python技术站

(0)
上一篇 2023年5月26日
下一篇 2023年5月26日

相关文章

  • Java工程mybatis实现多表查询过程详解

    关于Java工程mybatis实现多表查询的过程,我会为你提供详细的攻略。 什么是mybatis 先了解什么是mybatis,MyBatis是一个开源的、基于 Java 的持久层框架。通过XML描述符或注释来将对象与存储过程或 SQL 语句绑定起来,实现了将程序中的 Java 对象和数据库中的数据进行映射,使得数据的操作和 Java 代码的操作可以分离。 如…

    Java 2023年5月20日
    00
  • JavaSpringBoot报错“ConversionNotSupportedException”的原因和处理方法

    原因 “ConversionNotSupportedException” 错误通常是以下原因引起的: 类型转换错误:如果您的类型转换错误,则可能会出现此。在这种情况下,您需要检查您的类型转换并确保它们正确。 类型转换不支持:如果您的类型转换不支持,则可能会出现此。在这种情况下,您需要检查您的类型转换并确保它们受支持。 解决办法 以下是解决 “Conversi…

    Java 2023年5月4日
    00
  • Java异常类型及处理

    Java异常类型及处理攻略 异常定义 在程序执行时,如果出现某种错误或异常,则会产生异常。Java中所有的异常信息都是用异常类的形式传递的。在Java中,所有异常都是派生于Throwable类(它是 Java 语言中所有错误或异常的超类)的一个子类。它既包括异常(Exception)也包括错误(Error),它们有各自的特点: Exception Excep…

    Java 2023年5月26日
    00
  • SpringMVC 中HttpMessageConverter简介和Http请求415 的问题

    SpringMVC 中HttpMessageConverter简介和Http请求415 的问题 在SpringMVC中,HttpMessageConverter是用于将请求和响应的HTTP消息转换为Java对象的组件。本文将详细介绍HttpMessageConverter的作用和使用方法,并解决Http请求415的问题。 HttpMessageConvert…

    Java 2023年5月17日
    00
  • java FileOutputStream输出流的使用解读

    Java FileOutputStream 输出流的使用解读 在 Java 中,FileOutputStream 是一种字节流,用于将文件中的数据输出到指定位置。本文将为大家介绍如何使用 FileOutputStream。 创建 FileOutputStream 对象 要使用 FileOutputStream,需要先创建一个 FileOutputStream…

    Java 2023年5月26日
    00
  • Servlet实现分页效果

    下面是详细讲解如何在Servlet中实现分页效果的完整攻略: 第一步:获取总记录数 在进行分页时,需要先获取到数据的总记录数。可以通过查询数据表中的记录数或者使用一些第三方工具来获取。 第二步:设置每页显示的记录数和当前页码 需要设置每页显示的记录数和当前页码,这两个值通常是从前端传递过来的。为了避免一些异常情况,需要对这两个值做一些合法性验证。 // 获取…

    Java 2023年6月16日
    00
  • 替换jar包未重启引起的系统宕机事件

    一、事件背景: 某天凌晨,一阵急促的铃声将我从周公那里拉了过来,接听电话后,一脸懵逼。 什么情况?XX后台宕机了?当日日志也不打印了,前端发起的请求,都报超时,重启后又恢复了,不清楚会不会再次宕机。 出现这种情况,我第一时间想的是为什么是00:00:00宕机?难道后台嫌我这个大龄程序员睡得早了? 然后是通过远程视频,看日志,排查了凌晨之前的日志里的所有异常,…

    Java 2023年4月18日
    00
  • Tomcat服务器搭建教程

    Tomcat服务器搭建教程 安装JDK Tomcat服务器需要Java环境支持,因此需要先安装Java Development Kit (JDK)。 访问Oracle官方网站下载页面,选择合适的JDK版本下载。 安装JDK,设置环境变量。 下载Tomcat 访问Apache官网的下载页面,选择最新的稳定版本下载。 解压下载文件至目标文件夹。 配置Tomcat…

    Java 2023年5月19日
    00
合作推广
合作推广
分享本页
返回顶部