IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 2021-09-12 -> 正文阅读

[Java知识库]2021-09-12

java多线程锁解析(一)

首先,先来看一个最简单的java对象在jvm中加载后的二进制分布,简单展示一下代码

**
 * @Author xuzzhh
 * @Date 2021/9/12 16:20
 * @Version 1.0
 * @Since study
 */
public class ObjectHead {
    static  LHead lHead = new LHead();
    public static void main(String[] args){
        System.out.println("这是原有的对象头"+ClassLayout.parseInstance(lHead).toPrintable())}
   
    }
}
/**
 * @Author xuzzhh
 * @Date 2021/9/12 16:21
 * @Version 1.0
 * @Since study
 */
public class LHead {
}

执行效果如图所示
在这里插入图片描述

A区域中包含了未使用(1)+对象年龄(4)+是否可偏向(1)+锁类型(2)
途中00000101 表示对象年龄为0,可偏向,01表示偏向锁(java对象类型初始化时都是01偏向锁)
而在紧接A区域后边的地方会有两种情况:
(1):对象如果计算HashCode后的Hash值
(2):加锁后的持锁的线程ID
演示代码如下:

/**
 * @Author xuzzhh
 * @Date 2021/9/12 16:20
 * @Version 1.0
 * @Since study
 */
public class ObjectHead {
    static LHead lHead = new LHead();

    public static void main(String[] args) {
        System.out.println("这是原有的对象头" + ClassLayout.parseInstance(lHead).toPrintable());

        synchronized (lHead) {
            System.out.println(ClassLayout.parseInstance(lHead).toPrintable());
            System.gc();//手动进行一个GC,便于展现出对象的年龄变化
            System.out.println(ClassLayout.parseInstance(lHead).toPrintable());
        }
        System.out.println("这是Hash value" + Integer.toHexString(lHead.hashCode()));
        System.out.println("这是Hash 对象头" + ClassLayout.parseInstance(lHead).toPrintable());

    }
}

执行效果如下图:
在这里插入图片描述
从图上可以看出四种情况对应的执行结果,
(1):第一种为正常初始化后的对象头0(未使用) 0000(对象年龄为0) 1(可偏向) 01(偏向锁) ,线程ID或者Hashcode均为0。
(2):第二种执行结果为加锁后的执行结果,加锁后的对象结果变为对象头0(未使用) 0000(对象年龄为0) 1(可偏向) 01(偏向锁),与第一次执行结果不同的是,第二次出现了线程持有ID(00101000 01101100 00000011)对应的十六进制地址为(28 6c 03),这表示这个对象已经被一个线程持有锁了,并且从头部对象01可知,持有的是偏向锁。
(3):第三种执行结果是在二的情况下,手进行了一次GC,所以其对象的年龄进行了加1,其对象头的结果变为对象头0(未使用) 0001(对象年龄为1) 1(可偏向) 01(偏向锁),其余效果相对第二种情况无变化。
(4):第四种情况为执行了HashCode计算后的对象头0(未使用) 0001(对象年龄为1) 0(不可偏向) 01(偏向锁),计算了HashCode后,00110111 01101100 0110010000111101 后边的线程持有ID也变成了HashCode,将二进制转换为16进制后是37 6c 64 3d 由于计算机使用小端存储,所以实际的HashCode值为3d646c37,可以看见,计算HashCode后,对象头中的是否可偏向变成了不可偏向,而线程持有ID则变成了HashCode的值。
总结:
(1):当一把锁第一次进行加载的时候,对象头中出现的是偏向锁,当线程再次持有锁的时候依然会是偏向锁。
(2):当两个线程线程1和线程2交替执行时,对象头中的锁会膨胀为轻量级锁,
注:对象如果计算过HashCode后,可偏向标志为0,则表示不可偏向,此时即使是单个线程首次加锁,或者是两个线程交替执行持有对象锁,该锁依然会膨胀为轻量锁,所以在一般情况需要使用到偏向锁的时候,尽量不要对对象进行HashCode计算。
(3):当两个线程发生了资源竞争的时候,锁会膨胀为重量锁。
验证会在下一次更新中。

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-09-13 09:08:16  更:2021-09-13 09:08:56 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 16:58:57-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码