并发编程-锁膨胀
并发编程之锁膨胀预备知识
前言:记录一下并发编程的学习,做个笔记加深印象。并发编程学习的路神的视频。
目录
并发编程之锁膨胀预备知识
一、无锁
二、轻量锁
三、Header header = new Header();
四、线程加锁synchronized
五、线程释放锁(四中的t1释放锁)
一、无锁
无锁分为两种情况。
- 无锁可偏向(101)
- 无锁不可偏向(001)。在无锁不可偏向的情况下第一位偏向标识“0”表示不可偏向。但是还有一种情况也是101这种情况,那就是有锁且锁已经偏向了线程。
所以,看一把锁(对象)是否有锁,不能单纯看后三位,如果后三位是101,它可能是有锁,也可能是无锁。但是后三位如果是001那么肯定是无锁的,所以以后说的无锁基本都是指001.
二、轻量锁
后两位是00(一共是64位,前两62位都是一个指针,所以轻量级锁只需要看后两位00)
三、Header header = new Header();
一个对象new出来的时候是无锁可偏向的也就是后三位是101,其对象头的结构如下:其中bl=1,lock=01
public class Header {
}
public class TestDemo {
private static Logger logger = LoggerFactory.getLogger(TestDemo.class);
static Header header = new Header();
static Thread t1;
public static void main(String[] args) throws InterruptedException {
logger.info(ClassLayout.parseInstance(header).toPrintable());
}
}
/**
----------------------打印结果------------------
18:46:57.162 [main] INFO com.example.thread.TestDemo - com.example.thread.Header 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) 95 ef 00 f8 (10010101 11101111 00000000 11111000) (-134156395)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
结果分析:新建对象的对象头为101,其他位均为0
*/
四、线程加锁synchronized
使用一个线程t1来加锁synchronized,那么它必然是一个偏向锁,后三位同样是101,但是前面的值变了;存储了线程id和epoch等值,如下图:其中bl=1,lock=01(和3不同的是前面的值变了)
public class Header {
}
public class TestDemo {
private static Logger logger = LoggerFactory.getLogger(TestDemo.class);
static Header header = new Header();
static Thread t1;
public static void main(String[] args) throws InterruptedException {
logger.info("新建对象");
logger.info(ClassLayout.parseInstance(header).toPrintable());
t1 = new Thread(() -> testLock());
t1.setName("thread1");
t1.start();
Thread.sleep(500);
logger.info("释放锁之后");
logger.info(ClassLayout.parseInstance(header).toPrintable());
}
public static void testLock(){
synchronized (header){
logger.info("name :" + Thread.currentThread().getName());
logger.info(ClassLayout.parseInstance(header).toPrintable());
}
}
}
/**
----------------------打印结果----------------------
18:56:41.343 [main] INFO com.example.thread.TestDemo - 新建对象
# 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
18:56:42.078 [main] INFO com.example.thread.TestDemo - com.example.thread.Header 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) 95 ef 00 f8 (10010101 11101111 00000000 11111000) (-134156395)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
18:56:42.079 [thread1] INFO com.example.thread.TestDemo - name :thread1
18:56:42.080 [thread1] INFO com.example.thread.TestDemo - com.example.thread.Header object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 05 70 2b 0b (00000101 01110000 00101011 00001011) (187396101)
4 4 (object header) f5 7f 00 00 (11110101 01111111 00000000 00000000) (32757)
8 4 (object header) 95 ef 00 f8 (10010101 11101111 00000000 11111000) (-134156395)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
18:56:42.579 [main] INFO com.example.thread.TestDemo - 释放锁之后
18:56:42.580 [main] INFO com.example.thread.TestDemo - com.example.thread.Header object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 05 70 2b 0b (00000101 01110000 00101011 00001011) (187396101)
4 4 (object header) f5 7f 00 00 (11110101 01111111 00000000 00000000) (32757)
8 4 (object header) 95 ef 00 f8 (10010101 11101111 00000000 11111000) (-134156395)
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使用synchronized加锁的对象头结构还是101,只是前面的值变了。
*/
五、线程释放锁(四中的t1释放锁)
t1将锁释放(仅有t1加锁),由于锁是偏向锁,所以就算是释放了锁还是101,对象头和四中的一样。在四中的代码打印结果中也可以看见。