並發編程-鎖膨脹

  • 2021 年 1 月 30 日
  • 筆記

並發編程之鎖膨脹預備知識

前言:記錄一下並發編程的學習,做個筆記加深印象。並發編程學習的路神的影片。

目錄

並發編程之鎖膨脹預備知識

一、無鎖

二、輕量鎖

三、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,對象頭和四中的一樣。在四中的程式碼列印結果中也可以看見。

//www.dtmao.cc/news_show_656402.shtml