当前位置: 首页 > wzjs >正文

个人网站类型郑州网站建设蝶动

个人网站类型,郑州网站建设蝶动,有声小说网站开发,discuz论坛网站做的门户简介 锁升级,也可以理解为synchronized关键字的原理,是Java1.6中对synchronized关键字做的优化,锁升级涉及到对象的内存布局,在这里总结一下锁升级的过程和过程中对象内存布局的变化。 锁升级 锁升级:在JDK 1.6之前…

简介

锁升级,也可以理解为synchronized关键字的原理,是Java1.6中对synchronized关键字做的优化,锁升级涉及到对象的内存布局,在这里总结一下锁升级的过程和过程中对象内存布局的变化。

锁升级

锁升级:在JDK 1.6之前,Java内置锁还是一个重量级锁,是一个效率比较低下的锁,在JDK 1.6之后,为了提高锁的获取与释放效率,对synchronized的实现进行了优化,引入了偏向锁和轻量级锁,从此Java内置锁就有4种状态,级别由低到高依次为:无锁、偏向锁、轻量级锁和重量级锁。锁的4种状态会随着竞争的情况逐渐升级,而且是不可逆的过程,即不可降级。

锁升级的过程:

  • 无锁:对象刚创建的时候,处于无锁状态

  • 偏向锁:只有一个线程获取锁时,发现锁是无锁状态并且是可偏向的,会尝试把自己的线程id写入到对象头中,表示当前的锁是一个偏向锁。偏向锁的执行效率和无锁几乎相同,因为它只有第一次获取锁时,使用CAS算法,将线程ID设置到对象头中,之后,如果发现这个线程ID是自己,直接获取锁。由于偏向锁是为单个线程设计的,所以线程不会主动释放偏向锁,只有遇到其他线程尝试竞争偏向锁时,偏向锁才会被撤销。

  • 轻量级锁:偏向锁在有锁竞争时升级为轻量级锁。在轻量级锁下,没有获取到锁的线程不会阻塞而是自旋,如果同步代码块的执行时间较短并且竞争不激烈,自旋比阻塞导致的线程上下文切换带来的消耗要小。所以轻量级锁是在竞争不激烈的情况下使用自旋代替互斥。

  • 重量级锁:线程的自旋次数超过阈值之后,锁由轻量级锁升级为重量级锁,此时等待锁的线程都会进入阻塞状态,并且存放于一个监视器中,重量级锁的底层依赖monitor机制。

偏向锁的延迟加载:虚拟机在启动5秒之内创建的锁是轻量级锁,5秒之后创建的锁为偏向锁,这是虚拟机的优化措施。JVM会在一个安全点暂停持有偏向锁的线程,然后将用作锁的对象头中的偏向锁标识撤销,在这个安全点所有线程都停止工作,所以偏向锁的撤销可能会导致STW(世界暂停),影响服务的稳定性。

锁的升级是由JVM来进行的。

对象的内存布局

对象的内存布局描述了对象的数据结构。

查看java对象内存布局的方式:在项目中添加jar包 jol-core,jol的含义是java object layout,它是openjdk提供的工具包,可以用来查看对象的内存布局。

入门案例

查看一个Object类型的对象在内存中的布局,这算是最简单的对象了

步骤:第一步添加依赖、第二步打印对象的内存布局

<dependency><groupId>org.openjdk.jol</groupId><artifactId>jol-core</artifactId><version>0.9</version>
</dependency>
public static void main(String[] args) {Object obj = new Object();System.out.println(ClassLayout.parseInstance(obj).toPrintable());
}

结果:

在这里插入图片描述

jol依赖中的相关API:

  • ClassLayout:public class ClassLayout:存储了java对象的布局信息
    • parseInstance方法:public static ClassLayout parseInstance(Object instance, Layouter layouter):解析java对象的布局信息,生成ClassLayout对象
    • toPrintable方法:public String toPrintable():生成存储了布局信息的字符串

解析对象的内存布局

一个java对象在内存中包含三个部分:对象头、实例数据、对齐字节。

  • 对象头:存储对象的属性
  • 实例数据:也就是类中的成员变量,如果一个类有父类,实例数据也包含父类的成员变量。
  • 对齐字节:JVM要求java对象占的内存大小应该是CPU字长的倍数,所以后面有几个字节用于把对象的大小补齐至8的倍数

对象头

对象头的组成部分:对象头由mark word、类指针组成,如果对象是一个数组对象,还会有一个数组长度字段。

  • mark word:存储对象运行时的数据,如哈希值、gc分代年龄等,mark word中的数据会在运行时进行修改。mark word的长度是jvm一个字长的大小,也就是说32位JVM的Mark word为32位,64位JVM的Mark word为64位。

  • 类指针:class pointer,指向类对象的指针,jvm通过这个指针确定对象是哪个类的实例

  • 数组长度:array length,如果对象是一个数组,对象头还需要存储数组的长度

mark word

mark word是对象头中最复杂的地方,它存储的数据在运行时会被修改,例如,锁标志位、对象分代年龄、哈希值等,相比之下,类指针和数组长度都是常量,在运行时不会改变。

mark word中存储的数据:(截了两张网上的图)

  • 在64位的虚拟机上:

在这里插入图片描述

  • 在32位的虚拟机上:

在这里插入图片描述

mark word中存储的数据:不考虑对象的状态,只描述对象中存储的数据、数据的长度、数据的位置 (这里是基于64位的虚拟机)

  • 锁标志位:2bit,存放在第一个字节的最后两位,01表示无锁,00表示轻量级锁,10表示重量级锁,11是gc标记
  • 偏向锁标识:1bit,biased_lock,存放在lock之后,只占一个二进制位,为1时表示对象启用偏向锁,为0时表示对象没有偏向锁
  • 对象分代年龄:4bit,存储在biased_lock之后,在gc中,如果对象在survivor区复制一次,年龄增加1,当对象达到设定的阈值时,将会晋升到老年代
  • 哈希值:31bit,调用继承自Object类的hashCode方法后,生成的哈希值会存储到对象头中
  • 指向持有偏向锁的线程的指针:54bit,threadId
  • 偏向时间戳:2bit,epoch,记录线程获取了几次偏向锁
  • 在轻量级锁的状态下指向栈中锁的记录的指针:ptr_to_lock_record:62bit
  • 在重量级锁的状态下指向监视器(管程monitor)的指针:ptr_to_heavyweight_monitor:62bit

为什么偏向锁状态下mark word中存的是线程id,轻量级锁状态下mark word中存的是执行栈中锁记录的指针?如果是轻量级锁,当线程尝试获取锁时,若对象未被锁定,JVM会在该线程的栈帧中创建一个锁记录,并将对象的mark word复制到其中,随后,jvm使用cas操作将mark word更新为指向该锁记录的指针。这么做的好处是什么?支持锁重入:锁记录可以记录重入次数,线程每次重入锁时,锁记录会记录相关信息,释放锁时则减少重入次数,直到完全释放。

类指针

指向类对象的指针,jvm通过这个指针确定对象是哪个类的实例,

数组长度

如果是数组对象,对象头中会存储数组长度

成员变量

存储对象中的成员变量,就是用户可以通过getter、setter方法访问到的数据,要注意,如果一个类有父类,父类中成员变量的值也会被存储在这里。

对象的内存布局-实际案例

案例1:最简单的对象

以入门案例中的Object对象为例:
在这里插入图片描述

打印结果讲解:

  • 第一行:对象的类型,这里是Object类型
  • 第二行到倒数第三行之间是一个表格
    • 表格中的字段:
      • OFFSET:偏移量,对象头中的字段相对于对象头的偏移量,所以第一个字节的偏移量是0
      • SIZE:长度,以字节为单位
      • TYPE DESCRIPTION:类型描述,描述了对象中存储了什么数据
      • VALUE:每个字节中存储的数据分别用十六进制、二进制、和十进制进行了描述
    • 表格中的内容:
      • object header:表示存储的数据是对象头
      • loss due to the next object alignment:为了内存对齐而丢失一部分内存空间
  • 倒数第二行:Instance size,对象大小
  • 倒数第二行:Space losses,丢失的空间,这里为了内存对齐,有4字节的空间没有用。internal表示对象头内丢失的字节,external表示对象头外丢失的字节

要注意:无论是Windows系统,还是Linux系统,都是采用的小端存储法,在低地址存储低位数据。

详细讲解:
在这里插入图片描述

案例2:存储了数据的对象

一个存储了数据的对象:对象中存储了一个String、一个Integer、一个boolean值在这里插入图片描述

案例3:数组对象

一个int类型的数组类型的对象的内存布局,数组的长度是8

在这里插入图片描述

案例4:类对象

一个类对象的内存布局:

在这里插入图片描述

案例5:哈希值在对象头中的存储

在对象的正常状态下,从第二个字节开始,使用31比特位来存储哈希值

代码:

Object obj = new Object();
System.out.println("Integer.toBinaryString(obj.hashCode()) = " + Integer.toBinaryString(obj.hashCode()));
System.out.println(ClassLayout.parseInstance(obj).toPrintable());

执行结果:

在这里插入图片描述

结果解析:

  • 系统采用的是小端存储法,低地址存放的是低位数据
  • 哈希值的长度是31位,从第二个字节开始,到第五个字节的后7位,都是存储的哈希值,第五个字节的第一个比特位没有使用
  • 第五个字节的后7位对应的是哈希值的开头,第四个字节紧随其后,依次类推

解析内存布局时涉及到的知识点

大端法和小端法

大端法和小端法:描述了跨越多个字节的数据在内存中的存储方式

  • 小端法:低地址存放数据低位
  • 大端法:低地址存放数据高位

要注意,数据在存放时,字节是基本存储单元,无论是大端法还是小端法,存放数据的顺序都是从低地址到高地址,区别在于低地址存放低位数据还是高位数据。

Intel处理器采用小端存储法,Windows系统和Linux系统采用的都是Intel处理器。

内存对齐

CPU访问内存时,并不是逐个字节访问,而是以字长(word size)为单位访问,所以数据应该尽可能的放在内存地址是字长的倍数的位置,如果访问未对齐的内存,处理器需要做两次内存访问,而对齐的内存访问仅需要一次访问,内存对齐是使用空间换时间,提高了速度。内存对齐是由编译器来完成的

对齐系数:系数是指单项式中的数字因数,对齐系数是编译器做内存对齐时需要使用的常量,每个特定平台上的编译器都有自己的默认"对齐系数",常用平台默认对齐系数:32位系统对齐系数是4,代表4字节,64位系统对齐系数是8

指针压缩

在64位的虚拟机上并且堆内存小于32G时默认开启指针压缩,指向堆内存的指针会由64位被压缩到32位

指针压缩的jvm参数:-XX:+UseCompressedOops // java虚拟机的参数中, + 表示开启, - 表示关闭

案例1:查看虚拟机的参数

在命令行执行命令 java -XX:+PrintCommandLineFlags -version,也可以把这个命令添加到java程序中

打印结果:

-XX:InitialHeapSize=265280448 -XX:MaxHeapSize=4244487168 -XX:+PrintCommandLineFlags -XX:+UseCompressedClassPointers -XX:+UseCompressedOops  
-XX:UseLargePagesIndividualAllocation -XX:+UseParallelGC
java version "1.8.0_92"
Java(TM) SE Runtime Environment (build 1.8.0_92-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.92-b14, mixed mode)

结果解析:

  • InitialHeapSize:初始化堆内存大小,256M
  • MaxHeapSize:最大堆内存大小,4G
  • PrintCommandLineFlags:打印命令行参数
  • +UseCompressedClassPointers:压缩指向类对象的指针
  • +UseCompressedOops:压缩普通指针,oop,表示ordinary object pointers,普通java对象指针
案例2:关闭指针压缩

为Java程序添加虚拟机参数:-XX:-UseCompressedClassPointers -XX:-UseCompressedOops

查看结果:
在这里插入图片描述

结果解析:对象头占16个字节。因为没有开启指针压缩,锁指向类对象的指针是8个字节

锁升级过程中对象内存布局的变化

偏向锁

创建偏向锁的方式:

  • 第一种:加锁之前先让线程睡5秒。虚拟机在启动的5秒内创建的锁都不是偏向锁,这是虚拟机的一种优化措施
  • 第二种:加上JVM的运行参数,关闭偏向锁的延迟,相关参数:-XX:+UseBiasedLocking -XX:BiasedLockingStartupDelay=0

案例:

public static void main(String[] args){try {Thread.sleep(6000);} catch (InterruptedException e) {throw new RuntimeException(e);}// 程序启动5秒之后再创建对象Object LOCK = new Object();System.out.println("执行同步代码块之前: \n" + ClassLayout.parseInstance(LOCK).toPrintable());synchronized (LOCK) {System.out.println("获得锁的线程: \n"+ ClassLayout.parseInstance(LOCK).toPrintable());}System.out.println("执行同步代码块之后: \n" + ClassLayout.parseInstance(LOCK).toPrintable());
}

结果解析:

  • 执行同步代码块之前的对象:

在这里插入图片描述

  • 获得锁的线程

在这里插入图片描述

  • 执行同步代码块之后,线程偏向锁不会主动释放偏向锁,打印执行同步代码块之后的内存布局,和获得锁时的内存布局一模一样。

轻量级锁

案例:

private static final Object LOCK = new Object();public static void main(String[] args) {System.out.println("执行同步代码块之前: \n" + ClassLayout.parseInstance(LOCK).toPrintable());new Thread(LightWightLockTest::sync).start();try {Thread.sleep(1000L);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("执行同步代码块之后: \n" + ClassLayout.parseInstance(LOCK).toPrintable());
}private static void sync() {synchronized (LOCK) {System.out.println("获得锁的线程: \n" + Thread.currentThread().getName() + ": \n"+ ClassLayout.parseInstance(LOCK).toPrintable());}
}

案例讲解:在同步代码块内打印对象的内存布局,可以看到轻量级锁状态下对象头内的数据

在这里插入图片描述

同步代码块退出后,等1秒钟,再次打印锁对象的内存布局,发现轻量级锁已经变成无锁,指针数据也被清除。

重量级锁

案例:

private static final Object LOCK = new Object();public static void main(String[] args) {System.out.println("执行同步代码块之前: \n" + ClassLayout.parseInstance(LOCK).toPrintable());for (int i = 0; i < 2; i++) {new Thread(HeavyWeightTest::sync).start();}try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("执行同步代码块之后: \n"+ ClassLayout.parseInstance(LOCK).toPrintable());}private static void sync() {synchronized (LOCK) {System.out.println("获得锁的线程: \n"+ Thread.currentThread().getName() + ": \n"+ ClassLayout.parseInstance(LOCK).toPrintable());}
}

案例讲解:多个线程同时竞争,锁直接由无锁变成重量级锁

在这里插入图片描述

参考

  • https://www.cnblogs.com/mingyueyy/p/13054296.html
  • https://www.cnblogs.com/coderacademy/p/18204403

文章转载自:

http://QJGmj43W.bkjhx.cn
http://2oIx8IJ8.bkjhx.cn
http://w0W0uEpK.bkjhx.cn
http://uoPSAuYI.bkjhx.cn
http://12Gn6VOy.bkjhx.cn
http://cMitI1TC.bkjhx.cn
http://UQ9MfyXY.bkjhx.cn
http://OBNKBOBA.bkjhx.cn
http://KWWaRr9n.bkjhx.cn
http://xHYhvmZG.bkjhx.cn
http://LT3lWAah.bkjhx.cn
http://9c4XOrNh.bkjhx.cn
http://QgfOXdXx.bkjhx.cn
http://fVbKugje.bkjhx.cn
http://jLkWyO4f.bkjhx.cn
http://DQxrH0Zu.bkjhx.cn
http://XDmF8zGR.bkjhx.cn
http://FRCiUvUs.bkjhx.cn
http://JH9HZKYO.bkjhx.cn
http://sE6hOZOl.bkjhx.cn
http://OQdtMLo5.bkjhx.cn
http://5oFB6Jjt.bkjhx.cn
http://Us7gSLig.bkjhx.cn
http://8UMvOJlE.bkjhx.cn
http://AidvKZqu.bkjhx.cn
http://SygfDCmL.bkjhx.cn
http://6Bab5UYi.bkjhx.cn
http://BXf7mij7.bkjhx.cn
http://xT8dsRg7.bkjhx.cn
http://URh6PwoX.bkjhx.cn
http://www.dtcms.com/wzjs/756501.html

相关文章:

  • 网站建设丨找王科杰上词快低价网站建设行业现状
  • 萍乡土建设计网站高端访问
  • 广州网站推广平台鲜花网站开发与设计
  • 凡科网做网站好吗徐州建设工程交易网张周
  • 机关 网站 建设方案360浏览器下载
  • wordpress设置标题大小百度搜索优化怎么做
  • 网站建设开发综合实训报告网站接入银联支付怎么做
  • 网站后台管理是做一些什么WordPress验证问题
  • 网站推荐几个互联网网站名字
  • 外贸soho做网站怎么做网页模板之家免费下载
  • 个人网站页面设计作品商场大型话题活动策划网站
  • 高端品牌网站建设有哪些58.搜房等网站怎么做效果才好
  • 自家宽带怎么建设网站莱芜都市网二手车租车
  • 前端开发可以做网站运营吗net网站开发技术方案
  • 微网站开发框架南通专业网站建设报价
  • 如何做logo模板下载网站那里有制作网站企业
  • 怎么做自己的淘宝客推广网站家具企业网站建设
  • 站酷网官网入口wordpress crawling
  • 靖江网站建设公司开源网
  • 最早做弹幕的网站自己干电商如何下手
  • 网站添加漂浮二维码怎么做网站建设的课件
  • 网站设计网络推广关键词淮安做网站.卓越凯欣
  • 查企业信息怎么查网站优化流程图
  • 百元便宜建站东莞网站程序
  • 一个人做网站原型郑州百度公司地址
  • 农机公司网站建设汕头网站建设系统
  • 已有域名 搭建网站网站页面关键词优化
  • 网站名称及网址网站开发具体问题
  • 申请主机网站wordpress 自动 tag
  • 青岛红岛做网站做海报的软件app免费