一篇对对象锁的原理,存储位置的笔记
无锁:启动VM参数不配置,4s 程序开始执行,无锁 01偏向锁: JVM启动,默认延迟4s启动偏向锁。轻量级锁:synchronized (userEntity) 一个线程调用, 轻量级锁 00重量级锁:synchronized (userEntity) 多个线程争抢, 重量级锁 10
演示锁的几种状态
pom.xml
<dependency>
<groupId>org
.openjdk
.jol
</groupId
>
<artifactId>jol
-core
</artifactId
>
<version>0.8</version
>
</dependency
>
static UserEntity userEntity
;
public static void main(String
[] args
) throws Exception
{
userEntity
= new UserEntity();
out
.println("before lock");
out
.println(ClassLayout
.parseInstance(userEntity
).toPrintable());
Thread t1
= new Thread(()->{
synchronized (userEntity
){
try {
Thread
.sleep(5000);
} catch (InterruptedException e
) {
e
.printStackTrace();
}
}
});
t1
.start();
Thread
.sleep(1000);
out
.println("t1 lock ing");
out
.println(ClassLayout
.parseInstance(userEntity
).toPrintable());
sync();
out
.println("after lock");
out
.println(ClassLayout
.parseInstance(userEntity
).toPrintable());
System
.gc();
out
.println("after gc()");
out
.println(ClassLayout
.parseInstance(userEntity
).toPrintable());
}
private static void sync() {
synchronized (userEntity
){
try {
Thread
.sleep(4000);
} catch (InterruptedException e
) {
e
.printStackTrace();
}
}
}
result:
before lock
com.lxu.threadlocal.UserEntity 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) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
12 4 java.lang.String UserEntity.name null
16 4 java.lang.Integer UserEntity.age null
20 4 java.lang.String UserEntity.sex null
24 4 java.lang.String UserEntity.desc null
28 4 java.lang.Long UserEntity.create_time null
Instance size: 32 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
t1 lock ing
com.lxu.threadlocal.UserEntity object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 20 f5 9e 20 (00100000 11110101 10011110 00100000) (547288352)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
12 4 java.lang.String UserEntity.name null
16 4 java.lang.Integer UserEntity.age null
20 4 java.lang.String UserEntity.sex null
24 4 java.lang.String UserEntity.desc null
28 4 java.lang.Long UserEntity.create_time null
Instance size: 32 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
after lock
com.lxu.threadlocal.UserEntity object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) ca 1c 41 1d (11001010 00011100 01000001 00011101) (490806474)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
12 4 java.lang.String UserEntity.name null
16 4 java.lang.Integer UserEntity.age null
20 4 java.lang.String UserEntity.sex null
24 4 java.lang.String UserEntity.desc null
28 4 java.lang.Long UserEntity.create_time null
Instance size: 32 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
after gc()
com.lxu.threadlocal.UserEntity object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 09 00 00 00 (00001001 00000000 00000000 00000000) (9) // 00001001 第一位nouse,2-5 age ,6 是否是偏向锁, 7-8位 锁类别标识
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
12 4 java.lang.String UserEntity.name null
16 4 java.lang.Integer UserEntity.age null
20 4 java.lang.String UserEntity.sex null
24 4 java.lang.String UserEntity.desc null
28 4 java.lang.Long UserEntity.create_time null
Instance size: 32 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
00001001 第一位nouse,2-5 age ,6 是否是偏向锁, 7-8位 锁类别标识
调用hashcode 方法后,对象头 前56位 就不能存放偏向锁信息java 对象头组成: mark_word 8byte 、klass_word 4bytemark_word 64bit 由 hash、gc标识、是否偏向锁、lock 组成, 但格式不固定
锁类型对象头信息描述
偏向锁54bit threadinfo 2bit epoch、 gc 、1bit biasedlock轻量锁62-pro_to_record 、lock、重量锁62-ptr_to_monitorObject lock
① 无锁时 ② 偏向锁时 ③
锁的膨胀过程
如果调用wait()方法,会立即变成重量级锁两个线程逐个执行,依次为同一类的对象加锁多次,不满20次,锁升级 偏向锁-> 轻量锁 ,达20次,则jvm会把这个对象原来偏向的线程,全都指定为另一个线程,且这些对象都会不升级轻量锁,还是保持偏向锁, 偏向锁-> 轻量锁 复杂且费时
当jvm发现同一个线程,同一个类 在多次膨胀,就会发现这个类有问题,停止膨胀,批量偏量到指定线程 验证
public static void main(String
[] args
) throws InterruptedException
{
List
<A> list
= new ArrayList<>();
System
.out
.println("t1 start...");
Thread t1
= new Thread(() -> {
for (int i
= 0; i
< 25; i
++) {
System
.out
.println("111");
A a
= new A();
synchronized (a
){
list
.add(a
);
}
}
},"t1");
t1
.start();
t1
.join();
System
.out
.println("t2 before");
System
.out
.println(ClassLayout
.parseInstance(list
.get(1)).toPrintable());
Thread thread1
= new Thread(() -> {
int k
= 0;
for (A a
: list
) {
synchronized (a
){
if (k
== 21){
System
.out
.println("t2 ing");
System
.out
.println(ClassLayout
.parseInstance(a
).toPrintable());
}
k
++;
}
}
},"t2");
thread1
.start();
thread1
.join();
System
.out
.println("t2 after");
System
.out
.println(ClassLayout
.parseInstance(list
.get(1)).toPrintable());
}
result:
t1 start...
t2 before
com.lxu.th.A object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 05 d8 aa 1f (00000101 11011000 10101010 00011111) (531290117) // 00000101 101 标识偏向锁 531290117 标识偏向的线程
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
t2 ing
com.lxu.th.A object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 05 d9 bc 1f (00000101 11011001 10111100 00011111) (532470021) //达到20次以后,都为偏向锁,且偏向的线程ID 532470021 变了
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
t2 after //释放锁后
com.lxu.th.A object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1) // 01 无锁
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total