首页 > 技术文章 > 并发编程-锁膨胀

cnoneblog 2021-01-30 19:12 原文

并发编程之锁膨胀预备知识

前言:记录一下并发编程的学习,做个笔记加深印象。并发编程学习的路神的视频。

目录

并发编程之锁膨胀预备知识

一、无锁

二、轻量锁

三、Header header = new Header();

四、线程加锁synchronized

五、线程释放锁(四中的t1释放锁)


一、无锁

无锁分为两种情况。

  1. 无锁可偏向(101)
  2. 无锁不可偏向(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,对象头和四中的一样。在四中的代码打印结果中也可以看见。

http://www.dtmao.cc/news_show_656402.shtml

推荐阅读