对象头的锁类型
简单介绍一下各部分的含义
lock: 锁状态标记位,该标记的值不同,整个mark word表示的含义不同。
biased_lock:偏向锁标记,为1时表示对象启用偏向锁,为0时表示对象没有偏向锁。
1,age:Java GC标记位对象年龄。
2,identity_hashcode:对象标识Hash码,采用延迟加载技术。当对象使用HashCode()计算后,并会将结果写到该对象头中。当对象被锁定时,该值会移动到线程Monitor中。
3,thread:持有偏向锁的线程ID和其他信息。这个线程ID并不是JVM分配的线程ID号,和Java Thread中的ID是两个概念。
4,epoch:偏向时间戳。
5,ptr_to_lock_record:指向栈中锁记录的指针。
6,ptr_to_heavyweight_monitor:指向线程Monitor的指针。
- synchronized锁有
1,无锁
2,偏向锁 偏向锁的线程id 1(是否偏向) 01
3,轻量级锁 指向持有锁线程栈中锁记录的指针 0(时否偏向) 01
4,重量级锁 指向线程Monitor的指针 0(是否偏向) 10
下面的代码就是模拟锁的状态的变化,因为虚拟机加载时会延迟偏向锁的出现,所以睡5秒后就会变为偏向锁,但不偏向任何线程。
进行下面代码时你得先导入jol-core-0.9.jar,你可以区mvn仓库下载,
package com.qf1;
import org.openjdk.jol.info.ClassLayout;
public class Test3 {
static class A{}
public static void main(String[] args) throws InterruptedException {
Thread.sleep(5000);
A a = new A();
//初始时偏向锁,但是此时偏向id为0,谁都不偏向
System.out.println(ClassLayout.parseInstance(a).toPrintable());
//偏向锁,此时有偏向id,偏向main线程
synchronized (a) {
System.out.println("thread1 locking");
long l = System.nanoTime();
System.out.println(ClassLayout.parseInstance(a).toPrintable());
long l1 = System.nanoTime();
System.out.println((l1 - l) / 1000.0 / 1000.0);
}
Thread.sleep(4000);
//轻量级锁
Thread thread1 = new Thread() {
@Override
public void run() {
synchronized (a) {
System.out.println("--thread3 locking--");
long l = System.nanoTime();
System.out.println(ClassLayout.parseInstance(a).toPrintable());
long l1 = System.nanoTime();
System.out.println((l1 - l) / 1000.0 / 1000.0);
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
//thread2,thread3 从轻量级锁-->重量级,都是重量级锁,因为它们存在竞争,锁升级
Thread thread2 = new Thread() {
@Override
public void run() {
synchronized (a) {
System.out.println("thread1 locking");
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
long l = System.nanoTime();
System.out.println(ClassLayout.parseInstance(a).toPrintable());
long l1 = System.nanoTime();
System.out.println((l1 - l) / 1000.0 / 1000.0);
}
try {
//thread1退出同步代码块,且没有死亡
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
Thread thread3 = new Thread() {
@Override
public void run() {
synchronized (a) {
System.out.println("thread2 locking");
long l = System.nanoTime();
System.out.println(ClassLayout.parseInstance(a).toPrintable());
long l1 = System.nanoTime();
System.out.println((l1 - l) / 1000.0 / 1000.0);
}
try {
//thread1退出同步代码块,且没有死亡
Thread.sleep(3000);
System.out.println("线程死亡");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
//另一个线程获取main线程获取过的锁,此时main线程还存活,造成锁 偏向main线程锁->轻量级锁
thread1.start();
//延时确保让上一个线程执行完
Thread.sleep(3000);
thread2.start();
//让thread3延时,造成锁竞争
Thread.sleep(2000);
thread3.start();
}
}
当类被加载时,对象头中的锁记录会被延迟大概4点多秒
Thread.sleep(5000);
A a = new A();
System.out.println(ClassLayout.parseInstance(a).toPrintable());这时就会变为
**1 01创建时锁类型1就代表偏向锁,但此时还没有偏向任何线程;
com.qf1.LRU object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 05 38 6e 02 (00000101 00111000 01101110 00000010) (40777733)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 05 d6 00 f8 ( 00000101 11010110 00000000 11111000) (-134162939)
**1 01后面一大串代表偏向线程的id(不是thread.getid()的那个id)
1,什么时候变为轻量级锁呢?
一个线程对共享对象加锁访问完毕并释放了锁后,但该线程还没结束,此时另一个线程也来对共享资源访问加锁,这时共享对象中的锁就变为轻量级锁了;0 00
2,那什么时候变为重量级锁呢?
一个线程对共享对象加锁正在访问还未释放锁,此时另一个线程也来对共享资源访问加锁(等待),这时共享对象中的锁就变为重量级锁了;