1.什么是重量级锁
线程之间存在
实际的锁竞争行为
,线程间都有获取锁的需求,但是时间不可交错,互斥锁的等待
大白话就是:在同一时刻存在两个即两个以上线程对同一把锁产生竞争行为
2.重量级锁的案例
- Java case
public class Main {
public static void main(String[] args) throws InterruptedException {
Thread.sleep(5000);
Object objLock = new Object();
System.out.println(Thread.currentThread().getName() + " - " + ClassLayout.parseInstance(objLock).toPrintable());
new Thread(() -> {
synchronized (objLock){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println(Thread.currentThread().getName() + " - " + ClassLayout.parseInstance(objLock).toPrintable());
},"T1").start();
Thread.sleep(1000);
new Thread(() ->{
synchronized (objLock){
System.out.println(Thread.currentThread().getName() + " - " + ClassLayout.parseInstance(objLock).toPrintable());
}
},"T2").start();
new Thread(() ->{
synchronized (objLock){
System.out.println(Thread.currentThread().getName() + " - " + ClassLayout.parseInstance(objLock).toPrintable());
}
},"T3").start();
}
}
# WARNING: Unable to attach Serviceability Agent. You can try again with escalated privileges. Two options: a) use -Djol.tryWithSudo=true to try with sudo; b) echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
main - java.lang.Object 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) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
T1 - java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 05 30 41 d0 (00000101 00110000 01000001 11010000) (-801034235)
4 4 (object header) ff 7e 00 00 (11111111 01111110 00000000 00000000) (32511)
8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
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 - java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) ca 62 00 8c (11001010 01100010 00000000 10001100) (-1946131766)
4 4 (object header) ff 7e 00 00 (11111111 01111110 00000000 00000000) (32511)
8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
T3 - java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) ca 62 00 8c (11001010 01100010 00000000 10001100) (-1946131766)
4 4 (object header) ff 7e 00 00 (11111111 01111110 00000000 00000000) (32511)
8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
结合代码与输出结构进行分析
- 首先是在执行代码前对主线程(mian)进行了5s的阻塞,这样的目的是为了让偏向锁加载成功,到后面线程T1去获取锁对象的时候,此时的锁就是一个偏向锁
- 在T1线程的同步代码块中对T1线程进行了1s的阻塞,用来模拟线程持有锁,但是持有时间并不长
- 在创建T2线程前对主线程进行了1s的阻塞,这里是为了避免在同一时刻有超过一个线程对同一把锁的竞争,确保这里一定是T1先获取到锁(避免锁的膨胀导致锁最终变成重量级锁)
- 当创建T2线程获取锁的时候T1线程恰好使用完了锁,并释放了锁,此时T2线程会尝试通过CAS去修改Mark Word中的偏向线程ID,此时修改偏向线程ID失败,导致锁从偏向锁升级到轻量级锁,T2获取到锁执行同步代码
- 在同一时刻T3线程也发出了获取锁的申请,此时锁已经被T2线程占用并还未释放,此时T3会进行自旋重复的尝试获取锁,当自旋次数达到10次时还未申请到锁,此时锁将会进行膨胀升级为重量级锁(防止CPU空转)T2线程继续执行同步代码块,执行完成后释放锁,T3获取到锁执行同步代码块
版权声明:本文为ScholarTang原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。