Synchronized
public class TestSync {
static L l=new L();
static ReentrantLock reentrantLock=new ReentrantLock();
public static void main(String[] args) {
lockTest();
}
public static void lockTest(){
reentrantLock.lock();//给new出来的ReentrantLock上锁 改变这个对象里面的一个属性state 改为1 如果可以改成功就上锁成功
System.out.println("bbbb");
reentrantLock.unlock();
//锁的是代码块 并发包提供的锁
synchronized (l){//锁的是对象 java的内置锁
System.out.println("aaa");
}
//java对象的布局
}
}
synchronized改变的是对象的对象头
JAVA的对象组成 对象在堆上面分配内存分为 java对象的实例属性(不固定)、对象头(固定)和数据对齐(以64位虚拟机为例 它的对象的大小一定要是8的整数倍 如果不满足 就给该对象分配大于该大小的8的倍数的内存 去保存它 多出来的空间使用填充数据)
hotspot虚拟机的自动内存管理系统要求对象起始地址必须是8字节的整数倍
使用
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.9</version>
</dependency>
去辅助 看对象头
public class TestSync {
static L l=new L();
static ReentrantLock reentrantLock=new ReentrantLock();
public static void main(String[] args) {
//解析一个实例对象并打印
System.out.println(ClassLayout.parseInstance(l).toPrintable());
lockTest();
}
public static void lockTest(){
synchronized (l){//锁的是对象 java的内置锁
System.out.println("aaa");
}
//java对象的布局
}
}
可以看到 对象头为12个字节 对象实例为1个字节 3个为填充字节 总大小为16byte
损失了3个字节
只有对象头是固定的 实例数据与填充数据是动态的
1byte=8bit
什么是Java的对象头?
对象的第一个部分 所以对象都有的公共部分
Java的对象头的组成?
Mark Word+Class Metadata Address=12byte(64位) 96个bit
在这12个字节当中 包含对象的hashcode 、同步状态、GC状态,由两个词组成,
同步状态:是否加锁成功
GC状态:保存GC年龄
类型:保存对象是属于哪个类的 保存类的模板信息 放在源空间的模板信息 保存的是地址 即指针
词:即属性
一般来说 GC年龄到15次之后 就放到老年代
GC年龄 会记录到对象头 其中某个4位 上面 4bit 最大表示 16
一般来说 Java使用的虚拟机是HotSpot。
什么是jvm?什么是HotSpot?
jvm:是一个规范 一种标准 规定了对象头的组成
HotSpot:一个产品 一个实现 基于openjdk
openjdk:一个项目(代码)/c++项目 开源的HotSpot代码
Mark Word是什么?
在64位虚拟机中 占64bit 即8个字节 不固定
根据状态不同 存储的信息 是不固定的
无状态:25个bit 没有被使用 31个bit保存的是hashcode(当前对象存在于内存地址的地址,即将对象地址转换为hashcode) 1个bit 没有被使用 4个bit保存GC年龄 1个bit保存 偏向锁的偏向信息 2bit保存锁的信息
1.hashcode存在?
windows 使用的是小端存储 所以 图是倒的(16进制) 是倒序的
对象状态?
1.无状态 new出来的时候
2.偏向锁 只有一个线程持有该对象
3.轻量锁
4.重量锁 (synchronized)
5.gc标记
klass pointer/Class Metadata Address是什么?
在64位虚拟机中 占32bit 即4个字节
如果 虚拟机 没有开启指针压缩 那就是 64bit
类的源数据地址模板地址 最后的4个字节保存