对象实例化
创建对象的方式
可以先参考原来的:HotSpot虚拟机对象如何被创建的?
创建对象方式有:new、Class的newInstance()、Constructor的newInst(Xxx)、使用clone()、使用反序列化、第三方库Objenesis;
new创建方式
Student student = new Student();
Class的newInstance()创建方式
Class clazz = Class.forName("com.hong.Student");
Student student = (Student) clazz.newInstance();
Constructor的newInst(Xxx)的创建方式
public class Student{
private Integer age;
private String name;
public Student(Integer age,String name){
this.age = age;
this.name =name;
}
}
使用clone()创建方式
Student clone = student.clone();
使用反序列化
public class Student implements Serializable {
private String name;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public void say() {
System.out.println("hello i'm hong!"+this.age);
}
public static void main(String[] args) throws Exception {
Student student = new Student();
student.setAge(10);
String filePath = "com";
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filePath));
oos.writeObject(student);
oos.close();
System.out.println("序列化完成!");
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filePath));
Student student1 = (Student) ois.readObject();
ois.close();
student1.say();
System.out.println("反序列化完成!");
}
}
第三方库Objenesis创建对象
<dependency>
<groupId>org.objenesis</groupId>
<artifactId>objenesis</artifactId>
<version>3.0.1</version>
</dependency>
Objenesis objenesis = new ObjenesisStd();
ObjectInstantiator<Student> instantiator = objenesis.getInstantiatorOf(Student.class);
Student st1 = instantiator.newInstance();
st1.say();
System.out.println(st1.toString());
Student st2 = instantiator.newInstance();
st2.say();
System.out.println(st2.toString());
结果
hello i'm hong!null
com.Student@b1bc7ed
hello i'm hong!null
com.Student@7cd84586
创建对象的步骤
其它可以先参考两个文章:
内存布局
可以先参考原来的文章:对象的内存是如何布局的?
对象结构由对象头、对象体、对齐字节所组成。
由于其他都在上文已有相关的描述,本文主要针对Mark Word 来深入。
Klass Word
Klass Word对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。
Mark Word
Mark Word 默认存储对象是HashCode,分代年龄和锁标志位信息。Mark Word存储的数据会随着锁标志位的变化而变化。以下表是相关锁的锁状态。
可以通过查看 jdk8 markOop.hpp 源码注释。
HotSpot虚拟机对象头Mark Word(32位) | |||||
---|---|---|---|---|---|
锁状态 | 25bit | 4bit | 1bit | 2bit | |
23bit | 2bit | 偏向模式 | 标志位 | ||
未锁定 | 对象哈希码 | 分代年龄 | 0 | 01 | |
偏向锁 | 线程ID | Epoch | 分代年龄 | 1 | 01 |
轻量级锁定 | 指向调用栈中锁记录的指针 | 00 | |||
重量级锁定(锁膨胀) | 指向重量级锁的指针 | 10 | |||
GC标记 | 空 | 11 |
HotSpot虚拟机对象头Mark Word(64位) | ||||||
---|---|---|---|---|---|---|
锁状态 | 56bit | 1bit | 4bit | 1bit | 2bit | |
是否偏向锁 | 标志位 | |||||
未锁定 | unused:25bit | 对象hashCode:31bit | unused | 分代年龄 | 0 | 01 |
偏向锁 | 线程ID:54bit | Epoch:2bit | unused | 分代年龄 | 1 | 01 |
轻量级锁定 | 指向调用栈中锁记录的指针(ptr_to_lock_record) | 00 | ||||
重量级锁定(锁膨胀) | 指向互斥锁(重量级锁)的指针(ptr_to_heavyweight_monitor) | 10 | ||||
GC标记 | 空 | 11 |
相关说明:
标志位:区分锁的状态,最后两位为11时表示为GC回收状态。
是否偏向锁:由于未锁定和偏向锁的标志位都是01,所以引入一位是否偏向锁(biased_lock)来判断,当等于1时,则是偏向锁。
分代年龄:表示对象被GC的次数,当该次数到达阈值的时候,对象就会转移到老年代。
对象hashCode:运行期间调用System.identityHashCode()来计算,延迟计算,并把结果赋值到这里。当对象加锁后,计算的结果31位不够表示,在偏向锁,轻量锁,重量锁,hashcode会被转移到Monitor中。
偏向锁的线程ID1:偏向模式的时候,当某个线程持有对象的时候,对象这里就会被置为该线程的ID。在后面的操作中,就无需再进行尝试获取锁的动作。
epoch:偏向锁在CAS锁操作过程中,偏向性标识,表示对象更偏向哪个锁。
ptr_to_lock_record:轻量级锁状态下,指向栈中锁记录的指针。当锁获取是无竞争的时,JVM使用原子操作而不是OS互斥。这种技术称为轻量级锁定。在轻量级锁定的情况下,JVM通过CAS操作在对象的标题字中设置指向锁记录的指针。
ptr_to_heavyweight_monitor:重量级锁状态下,指向对象监视器Monitor的指针。如果两个不同的线程同时在同一个对象上竞争,则必须将轻量级锁定升级到Monitor以管理等待的线程。在重量级锁定的情况下,JVM在对象的ptr_to_heavyweight_monitor设置指向Monitor的指针。
相关校验过程
引入jar包
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.8</version>
</dependency>
jol-core 常用的三个方法
ClassLayout.parseInstance(object).toPrintable():查看对象内部信息.
GraphLayout.parseInstance(object).toPrintable():查看对象外部信息,包括引用的对象.
GraphLayout.parseInstance(object).totalSize():查看对象总大小.
普通对象
package com;
import org.objenesis.Objenesis;
import org.objenesis.ObjenesisStd;
import org.objenesis.instantiator.ObjectInstantiator;
import org.openjdk.jol.info.ClassLayout;
import java.io.*;
/**
* @author: csh
* @Date: 2021/2/8 17:47
* @Description:验证equals错误
*/
public class Student implements Serializable {
private String name;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public void say() {
System.out.println("hello i'm hong!"+this.age);
}
public static void main(String[] args) throws Exception {
Student student = new Student();
System.out.println(ClassLayout.parseInstance(student).toPrintable());
}
}
默认开启压缩指针
com.Student object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 05 c1 00 f8 (00000101 11000001 00000000 11111000) (-134168315)
12 4 java.lang.String Student.name null
16 4 java.lang.Integer Student.age null
20 4 (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
可以看到有 OFFSET、SIZE、TYPE DESCRIPTION、VALUE 这几个名词头,它们的含义分别是
OFFSET:偏移地址,单位字节;
SIZE:占用的内存大小,单位为字节;
TYPE DESCRIPTION:类型描述,其中object header为对象头;
VALUE:对应内存中当前存储的值,二进制32位;
可以看到对象实例占了24 byte(192 bit(位)) ,对象头占12 byte(96 bit),其中对象头mark word 占据了8 byte(64 bit), kclass point占据4 byte(32 bit),填充4 byte(32 bit),这里直接证明:
padding为8个字节成整数倍;
jdk8默认开始压缩指针;
关闭压缩指针
-XX:-UseCompressedOops
com.Student object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 00 34 b6 1c (00000000 00110100 10110110 00011100) (481702912)
12 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
16 8 java.lang.String Student.name null
24 8 java.lang.Integer Student.age null
Instance size: 32 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
可以发现关闭了压缩指针这个体积变成32 bytes(256 bit),32-24=8 足足大了64 bit,所以,可以得知,没有开启压缩指针是没有填充的。
数组对象
int[] arr = {1,2,3};
System.out.println(ClassLayout.parseInstance(arr).toPrintable());
结果
开启压缩
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 6d 01 00 f8 (01101101 00000001 00000000 11111000) (-134217363)
12 4 (object header) 03 00 00 00 (00000011 00000000 00000000 00000000) (3)
16 12 int [I.<elements> N/A
28 4 (loss due to the next object alignment)
Instance size: 32 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
可以看到对象实例占了32 byte(256 bit(位)) ,对象头占12 byte(96 bit),其中对象头mark word 占据了8 byte(64 bit), kclass point占据4 byte(32 bit),实例对象占据 12 byte(96 bit),填充4 byte(32 bit):
关闭压缩
-XX:-UseCompressedOops
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 68 0b d0 1b (01101000 00001011 11010000 00011011) (466619240)
12 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
16 4 (object header) 03 00 00 00 (00000011 00000000 00000000 00000000) (3)
20 4 (alignment/padding gap)
24 12 int [I.<elements> N/A
36 4 (loss due to the next object alignment)
Instance size: 40 bytes
Space losses: 4 bytes internal + 4 bytes external = 8 bytes total
可以发现关闭了压缩指针这个体积变成40 bytes(320 bit),40-32=8 足足大了64 bit,所以,可以得知,没有开启压缩指针是没有填充的。
JVM锁的升级过程
在jdk1.6的时候还只有重量级锁,到了jdk1.7引入了偏向锁、轻量级锁,至此以后,锁分为:无锁、偏向锁、轻量级锁、重量级锁。
不同的锁,意味意性能和开销都不一样,以及锁是如何慢慢升级为重量级锁的呢?
创建一个新对象默认为无锁,尝试加偏向锁,当偏向锁竞争稍微激烈则升级为轻量级锁,如果竟争再加剧则升级为重量级锁。
验证锁升级
HotSpot虚拟机对象头Mark Word(64位) | ||||||
---|---|---|---|---|---|---|
锁状态 | 56bit | 1bit | 4bit | 1bit | 2bit | |
是否偏向锁 | 标志位 | |||||
未锁定 | unused:25bit | 对象hashCode:31bit | unused | 分代年龄 | 0 | 01 |
偏向锁 | 线程ID:54bit | Epoch:2bit | unused | 分代年龄 | 1 | 01 |
轻量级锁定 | 指向调用栈中锁记录的指针(ptr_to_lock_record) | 00 | ||||
重量级锁定(锁膨胀) | 指向互斥锁(重量级锁)的指针(ptr_to_heavyweight_monitor) | 10 | ||||
GC标记 | 空 | 11 |
无锁状态
未锁定 | unused:25bit | 对象hashCode:31bit | unused | 分代年龄 | 0 | 01 |
---|
package com.lock;
import org.openjdk.jol.info.ClassLayout;
/**
* @author: csh
* @Date: 2021/5/11 11:03
* @Description:无锁
*/
public class UnLock {
public static void main(String[] args) {
UnLock unLock = new UnLock();
System.out.println("前:"+ClassLayout.parseInstance(unLock).toPrintable());
System.out.println(unLock.hashCode());
System.out.println("后:"+ClassLayout.parseInstance(unLock).toPrintable());
}
}
结果
前:com.lock.UnLock object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 05 c1 00 f8 (00000101 11000001 00000000 11111000) (-134168315)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
999661724
后:com.lock.UnLock object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 9c a0 95 (00000001 10011100 10100000 10010101) (-1784636415)
4 4 (object header) 3b 00 00 00 (00111011 00000000 00000000 00000000) (59)
8 4 (object header) 05 c1 00 f8 (00000101 11000001 00000000 11111000) (-134168315)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
可以看出,没有计算hashcode的时候这个值还是00,而计算后变成01,这个就与上面的无锁一致!
偏向锁状态&匿名偏向锁状态
偏向锁 | 线程ID:54bit | Epoch:2bit | unused | 分代年龄 | 1 | 01 |
---|
当一个对象已经计算过 identity hash code(例如存在有执行 hashcode 的操作),它就无法进入偏向锁状态
当一个对象正在处于偏向锁状态,如果需要计算其 identify hash code 的话,则它的偏向锁会被撤销,并且锁会膨胀为重量锁
重量锁的实现中,ObjectMonitor 类里有字段可以记录非加锁状态下的 mark word,其中可以存储 identity hash code 的值
由于是小端排序,所以要反着来。
package com.lock;
import org.openjdk.jol.info.ClassLayout;
/**
* @author: csh
* @Date: 2021/5/11 11:16
* @Description:偏向锁
*/
public class PartialLock {
static PartialLock partialLock = new PartialLock();
public static void main(String[] args) throws InterruptedException {
Thread.sleep(5000);
System.out.println("未锁"+ClassLayout.parseInstance(partialLock).toPrintable());
synchronized (partialLock) {
System.out.println("加锁"+ClassLayout.parseInstance(partialLock).toPrintable());
}
}
}
结果:
"C:\Program Files\Java\jdk1.8.0_181\bin\java.exe" -Dvisualvm.id=1104954274125300 -XX:+UseBiasedLocking -XX:BiasedLockingStartupDelay=0 "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2018.2.3\lib\idea_rt.jar=58652:C:\Program Files\JetBrains\IntelliJ IDEA 2018.2.3\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_181\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\rt.jar;D:\ideaWorkSpace\jdk8\target\classes;D:\mvn\junit\junit\4.13.2\junit-4.13.2.jar;D:\mvn\org\hamcrest\hamcrest-core\1.3\hamcrest-core-1.3.jar;D:\mvn\org\objenesis\objenesis\3.0.1\objenesis-3.0.1.jar;D:\mvn\org\openjdk\jol\jol-core\0.8\jol-core-0.8.jar" com.lock.PartialLock
未锁com.lock.PartialLock object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 05 00 00 00 (00000101 00000000 00000000 00000000) (5)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 05 c1 00 f8 (00000101 11000001 00000000 11111000) (-134168315)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
加锁com.lock.PartialLock object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 05 38 20 03 (00000101 00111000 00100000 00000011) (52443141)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 05 c1 00 f8 (00000101 11000001 00000000 11111000) (-134168315)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
Process finished with exit code 0
颜色代表:是否偏向、锁标记
小端排序:
00000101 00111000 00100000 00000011 00000000 00000000 00000000 00000000
大端排序:
00000000 00000000 00000000 00000000 00000011 00100000 00111000 00000101
轻量级锁
轻量级锁定 | 指向调用栈中锁记录的指针(ptr_to_lock_record) | 00 |
---|
package com.lock;
import org.openjdk.jol.info.ClassLayout;
/**
* @author: csh
* @Date: 2021/5/11 14:38
* @Description:轻量级锁状态
*/
public class GentlyLock {
public static void main(String[] args) throws InterruptedException {
Thread.sleep(5000);
final GentlyLock gentlyLock = new GentlyLock();
synchronized (gentlyLock){
System.out.println("偏向锁"+ClassLayout.parseInstance(gentlyLock).toPrintable());
}
new Thread(() -> {
synchronized (gentlyLock){
System.out.println("轻量级锁"+ClassLayout.parseInstance(gentlyLock).toPrintable());
}
}).start();
}
}
结果
"C:\Program Files\Java\jdk1.8.0_181\bin\java.exe" -Dvisualvm.id=1106556182703499 "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2018.2.3\lib\idea_rt.jar=60327:C:\Program Files\JetBrains\IntelliJ IDEA 2018.2.3\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_181\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\rt.jar;D:\ideaWorkSpace\jdk8\target\classes;D:\mvn\junit\junit\4.13.2\junit-4.13.2.jar;D:\mvn\org\hamcrest\hamcrest-core\1.3\hamcrest-core-1.3.jar;D:\mvn\org\objenesis\objenesis\3.0.1\objenesis-3.0.1.jar;D:\mvn\org\openjdk\jol\jol-core\0.8\jol-core-0.8.jar" com.lock.GentlyLock
偏向锁com.lock.GentlyLock object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 05 38 e3 02 (00000101 00111000 11100011 00000010) (48445445)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 05 c1 00 f8 (00000101 11000001 00000000 11111000) (-134168315)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
轻量级锁com.lock.GentlyLock object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 80 f7 01 20 (10000000 11110111 00000001 00100000) (536999808)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 05 c1 00 f8 (00000101 11000001 00000000 11111000) (-134168315)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
Process finished with exit code 0
颜色代表:是否偏向、锁标记
偏向锁
小端排序:00000101 00111000 11100011 00000010 00000000 00000000 00000000 00000000
大端排序:00000000 00000000 00000000 00000000 00000010 11100011 00111000 00000101
轻量级锁
小端排序:10000000 11110111 00000001 00100000 00000000 00000000 00000000 00000000
大端排序:00000000 00000000 00000000 00000000 00100000 00000001 11110111 10000000
重量级锁
重量级锁定(锁膨胀) | 指向互斥锁(重量级锁)的指针(ptr_to_heavyweight_monitor) | 10 |
---|
package com.lock;
import org.openjdk.jol.info.ClassLayout;
/**
* @author: csh
* @Date: 2021/5/11 17:34
* @Description:重量级锁
*/
public class WeightLock {
static WeightLock weightLock = new WeightLock();
public static void main(String[] args) throws InterruptedException {
Thread.sleep(1000);
new Thread(()->{
synchronized (weightLock) {
try {
weightLock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(ClassLayout.parseInstance(weightLock).toPrintable());
}
}).start();
Thread.sleep(5000);
synchronized (weightLock){
weightLock.notifyAll();
}
}
}
结果
"C:\Program Files\Java\jdk1.8.0_181\bin\java.exe" -Dvisualvm.id=1117453392924400 "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2018.2.3\lib\idea_rt.jar=55196:C:\Program Files\JetBrains\IntelliJ IDEA 2018.2.3\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_181\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\rt.jar;D:\ideaWorkSpace\jdk8\target\classes;D:\mvn\junit\junit\4.13.2\junit-4.13.2.jar;D:\mvn\org\hamcrest\hamcrest-core\1.3\hamcrest-core-1.3.jar;D:\mvn\org\objenesis\objenesis\3.0.1\objenesis-3.0.1.jar;D:\mvn\org\openjdk\jol\jol-core\0.8\jol-core-0.8.jar" com.lock.WeightLock
com.lock.WeightLock object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) ea 36 5e 1c (11101010 00110110 01011110 00011100) (475936490)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 05 c1 00 f8 (00000101 11000001 00000000 11111000) (-134168315)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
Process finished with exit code 0
颜色代表:是否偏向、锁标记
小端排序:
11101010 00110110 01011110 00011100 00000000 00000000 00000000 00000000
大端排序:
00000000 00000000 00000000 00000000 00011100 01011110 00110110 11101010
总结:从上面可以验证到不同的锁升级后的验证方式以及展现。
最后
重新了解关于对象与内存布局,特别这块锁升级,是多线程的基础以及从jvm层面来学习锁这块,会更容易理解关于synchronized 以及后续多线程深入的知识及性能考量。本文参考了大量的相关可靠性文档以及相关的学习资料,耗费比较大的精力,因为这块的确比较深入了,也非常值得学习。
参考文献
https://www.cnblogs.com/yxym2016/p/12920315.html
https://blog.csdn.net/qq_26542493/article/details/90938070
https://gorden5566.com/post/1019.html
https://blog.csdn.net/qq_36434742/article/details/106854061
https://zhuanlan.zhihu.com/p/50984945
https://www.cnblogs.com/jajian/p/13681781.html
https://www.cnblogs.com/cxuanBlog/p/11684390.html
https://www.cnblogs.com/dongl961230/p/13275011.html https://docs.oracle.com/javase/7/docs/technotes/guides/vm/performance-enhancements-7.html
https://www.yuque.com/u500486/java/ga07ka