Java多线程(二) - Java对象结构与对象锁的升级

一、Java 对象结构

Java 对象在 JVM 中的结构主要包括三部分:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding)。

其中,对象头是一个非常关键的部分,因为它包含了对象运行时的关键信息,如锁状态、哈希码等。

对象头(Header) 主要包含两部分:

  1. Mark Word(标记字):用于存储对象自身的运行时数据,如 GC 标志位、哈希码、锁状态等信息。这部分信息在 JVM 中起着至关重要的作用,尤其是在多线程同步时。Mark Word 的大小和具体结构会根据 JVM 的实现和版本有所不同,但通常包括锁状态、偏向锁标识、指向锁记录的指针等。

  2.  Class Pointer(类对象指针):用于存放方法区 Class 对象的地址,通过这个指针,虚拟机可以确定这个对象是哪个类的实例。

如果对象是一个 Java 数组,则还会包含一个Array Length(数组长度)字段,用于记录数组的长度。

二、对象锁的升级

在 Java 中,synchronized 关键字用于控制多线程同步,保证访问共享资源时的线程安全。

在 JDK 1.6 之前,synchronized 实现的是重量级锁,效率较低。

从 JDK 1.6 开始,JVM 对 synchronized 进行了优化,引入了偏向锁和轻量级锁,以提高锁的获取与释放效率。

Java 内置锁的状态总共有四种,级别由低到高依次为:无锁、偏向锁、轻量级锁和重量级锁。这些状态会随着线程的竞争情况逐渐升级,且是不可逆的过程,即锁可以升级但不能降级。

锁升级过程

  1.  无锁状态:对象刚被创建时,没有任何线程来竞争,处于无锁状态。此时,偏向锁标识位是 0,锁状态为 01。

  2.  偏向锁状态:当某个线程第一次访问某个同步代码块时,JVM 会将其设置为偏向锁状态,表示这个锁偏爱该线程。此后,只要该线程再次访问这个同步代码块,就可以直接获得锁,而无需进行任何检查和切换。偏向锁在竞争不激烈的情况下效率非常高。

  3.  轻量级锁状态:当有其他线程尝试访问同一个同步代码块时,偏向锁状态会被撤销,并升级为轻量级锁状态。轻量级锁通过自旋锁的方式来实现,即线程会循环等待锁的释放,而不会立即阻塞。如果持有锁的线程能在很短时间内释放锁,那么等待的线程就可以立即获得锁,从而避免了线程阻塞和唤醒的开销。

  4.  重量级锁状态:如果轻量级锁自旋尝试获取锁失败,或者持有锁的线程执行时间较长,超过了自旋等待的最大时间,那么轻量级锁会膨胀为重量级锁。此时,线程会被阻塞,并等待持有锁的线程释放锁。重量级锁通过对象监视器(Monitor)来实现,线程会进入阻塞队列,等待锁的释放。

package com.hmblogs.backend.study.thread;

public class UpgradeThread {
    // 示例代码,展示如何在多线程环境中安全地升级对象结构

    // 假设的对象结构
    static class MyObject {
        int version;
        Object data;

        MyObject(int version, Object data) {
            this.version = version;
            this.data = data;
        }

        void upgrade(MyObject newVersion) {
            // 这里可以加入升级前的检查,如版本比较等
            synchronized (this) {
                this.version = newVersion.version;
                this.data = newVersion.data; // 执行实际的升级操作
            }
        }
    }

    // 升级线程
    static class UpgradeThread2 extends Thread {
        MyObject currentObject;
        MyObject newVersion;

        UpgradeThread2(MyObject currentObject, MyObject newVersion) {
            this.currentObject = currentObject;
            this.newVersion = newVersion;
        }

        @Override
        public void run() {
            currentObject.upgrade(newVersion);
        }
    }

    public static void main(String[] args) {
        MyObject currentObject = new MyObject(1, "version 1 data");
        MyObject newVersion = new MyObject(2, "version 2 data");

        Thread upgradeThread = new UpgradeThread2(currentObject, newVersion);
        upgradeThread.start();
        // 确保升级线程执行完成
        try {
            upgradeThread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // 打印升级后的对象数据
        System.out.println("Current version: " + currentObject.version);
        System.out.println("Current data: " + currentObject.data);
    }
}

这个代码示例展示了如何在 Java 中创建一个简单的对象结构,并在多线程环境中安全地升级它。

MyObject 类包含了一个 upgrade 方法,该方法通过同步块来保证在多线程条件下的安全升级操作。

UpgradeThread 类继承自 Thread,用于执行升级动作。

在 main 方法中,我们创建了两个版本的对象实例,并启动了一个新的线程来执行升级操作。

最后,我们等待线程执行完成并打印升级后的对象数据。

总的来说,Java 对象锁的升级是为了提高多线程同步的效率,减少锁的获取和释放的开销。

通过引入偏向锁和轻量级锁,JVM 能够在多线程竞争不激烈的情况下,以较低的开销实现同步,从而提高程序的性能。

  • 12
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值