Syn筆記--jol查看對象頭

jol查看對象頭來分析一波synchronize關鍵字加鎖過程

synchronize在jdk1.5之前就是一個重量級的鎖,是在jvm層面加鎖的一種形式,在字節碼運行的過程中被翻譯成了兩個指令,速度很慢。jkd1.6開始對synchronize進行了非常多的優化,使sync有了一個鎖升級機制,可以讓sync在不同的場景下加不同的鎖,大大提升了sync的效率。sync一共有三種鎖狀態:偏向鎖、輕量級鎖、重量級鎖。下面通過查看class對象頭的方式來查看這幾個鎖狀態是怎麼表現的。

import org.openjdk.jol.info.ClassLayout;
import org.openjdk.jol.vm.VM;
import static java.lang.System.out;

public class JOLExample1 {
    public static void main(String[] args) throws Exception {
        A a = new A();
        out.println(VM.current().details());
        out.println(ClassLayout.parseInstance(a).toPrintable());
    }
}
# Running 64-bit HotSpot VM.
# Using compressed oop with 3-bit shift.
# Using compressed klass with 3-bit shift.
# Objects are 8 bytes aligned.
# Field sizes by type: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]
# Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]

com.wave.test.A 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        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

通過查看value可以發現沒有加鎖的對象的狀態是01(無鎖狀態)。

偏向鎖在對象頭上有一個bit用來標識偏向狀態,所以如果是101就是偏向鎖

import org.openjdk.jol.info.ClassLayout;
import org.openjdk.jol.vm.VM;
import static java.lang.System.out;
//沒有競爭,理論上是偏向鎖
public class JOLExample2 {
    static A a;
    public static void main(String[] args)throws Exception{
        a = new A();
        out.println("befre lock");
        out.println(ClassLayout.parseInstance(a).toPrintable());
        sync();
        out.println("after lock");
        out.println(ClassLayout.parseInstance(a).toPrintable());
    }
    public static void sync() throws InterruptedException {
        synchronized (a){
            System.out.println("我也不知道要打印什麼");
        }
    }
}

神奇的發現加了鎖還是01,這裏是因爲偏向鎖會有一個4s的延遲,修改虛擬機參數或者睡眠5s就可以看到101了(XX:+UseBiasedLocking -XX:BiasedLockingStartupDelay=0)

befre lock
com.wave.test.A 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        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

我也不知道要打印什麼
after lock
com.wave.test.A 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        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

一個對象如果被兩個線程加了鎖,那就會變成輕量級鎖,如果被兩個線程競爭了,就會變成重量級鎖

//輕量級鎖
public class JOLExample3 {
    static A a;
    public static void main(String[] args)throws Exception{
        //Thread.sleep(5000);
        a = new A();
        out.println("befre lock");
         new Thread(()->{
            sync();
        }).start();
        Thread.sleep(10000);//如果減小這個值,讓兩個線程發生競爭,就會產生重量級鎖
        out.println("after lock");
        //out.println(ClassLayout.parseInstance(a).toPrintable());
        sync();

    }
    public static void sync() {
        synchronized (a){
            try {
                out.println(ClassLayout.parseInstance(a).toPrintable());
            }catch (Exception e){
            }

        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章