JVM学习笔记13 synchronized

bilibili-JVM学习笔记13 synchronized
The Java Virtual Machine Specification - Java SE 8 Edition

JVM学习笔记11 - Java字节码初识
JVM学习笔记12 - 解读笔记11中的attributes

实例方法加 synchronized

package new_package.jvm.p46;

public class SynchronizedTest1 {

    private int i = 0;

    public synchronized void test1() {
        i++;
        System.out.println(i);
    }
}

javap -verbose -p new_package.jvm.p46.SynchronizedTest1

Classfile /Users/kevin/Documents/opensource/gitee/java-read-sources-sample/target/classes/new_package/jvm/p46/SynchronizedTest1.class
  Last modified 2020-6-10; size 558 bytes
  MD5 checksum 1a105be1126b77561dc33fa15d28ea0e
  Compiled from "SynchronizedTest1.java"
public class new_package.jvm.p46.SynchronizedTest1
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #6.#19         // java/lang/Object."<init>":()V
   #2 = Fieldref           #5.#20         // new_package/jvm/p46/SynchronizedTest1.i:I
   #3 = Fieldref           #21.#22        // java/lang/System.out:Ljava/io/PrintStream;
   #4 = Methodref          #23.#24        // java/io/PrintStream.println:(I)V
   #5 = Class              #25            // new_package/jvm/p46/SynchronizedTest1
   #6 = Class              #26            // java/lang/Object
   #7 = Utf8               i
   #8 = Utf8               I
   #9 = Utf8               <init>
  #10 = Utf8               ()V
  #11 = Utf8               Code
  #12 = Utf8               LineNumberTable
  #13 = Utf8               LocalVariableTable
  #14 = Utf8               this
  #15 = Utf8               Lnew_package/jvm/p46/SynchronizedTest1;
  #16 = Utf8               test1
  #17 = Utf8               SourceFile
  #18 = Utf8               SynchronizedTest1.java
  #19 = NameAndType        #9:#10         // "<init>":()V
  #20 = NameAndType        #7:#8          // i:I
  #21 = Class              #27            // java/lang/System
  #22 = NameAndType        #28:#29        // out:Ljava/io/PrintStream;
  #23 = Class              #30            // java/io/PrintStream
  #24 = NameAndType        #31:#32        // println:(I)V
  #25 = Utf8               new_package/jvm/p46/SynchronizedTest1
  #26 = Utf8               java/lang/Object
  #27 = Utf8               java/lang/System
  #28 = Utf8               out
  #29 = Utf8               Ljava/io/PrintStream;
  #30 = Utf8               java/io/PrintStream
  #31 = Utf8               println
  #32 = Utf8               (I)V
{
  public new_package.jvm.p46.SynchronizedTest1();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: aload_0
         5: iconst_0
         6: putfield      #2                  // Field i:I
         9: return
      LineNumberTable:
        line 8: 0
        line 10: 4
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      10     0  this   Lnew_package/jvm/p46/SynchronizedTest1;

  public synchronized void test1();
    descriptor: ()V
    flags: ACC_PUBLIC, ACC_SYNCHRONIZED
    Code:
      stack=3, locals=1, args_size=1
         0: aload_0
         1: dup
         2: getfield      #2                  // Field i:I
         5: iconst_1
         6: iadd
         7: putfield      #2                  // Field i:I
        10: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
        13: aload_0
        14: getfield      #2                  // Field i:I
        17: invokevirtual #4                  // Method java/io/PrintStream.println:(I)V
        20: return
      LineNumberTable:
        line 13: 0
        line 14: 10
        line 15: 20
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      21     0  this   Lnew_package/jvm/p46/SynchronizedTest1;
}
SourceFile: "SynchronizedTest1.java"

解析:

  • 并没有 monitor 指令
  • 方法标识符上标有 ACC_SYNCHRONIZED
  • test1 方法没有入参,然而 args_size=1
    • 这是因为每个非静态方法,编译器会自动在第一个位置添加一个参数 this ,指向当前实例

实例方法体内部加 synchronized

package new_package.jvm.p46;

public class SynchronizedTest2 {

    private Object lock = new Object();

    private int i = 0;

    public void test1() {

        synchronized (lock) {
            i++;
        }

        System.out.println(i);
    }
}

javap -verbose -p new_package.jvm.p46.SynchronizedTest2

Classfile /Users/kevin/Documents/opensource/gitee/java-read-sources-sample/target/classes/new_package/jvm/p46/SynchronizedTest2.class
  Last modified 2020-6-10; size 734 bytes
  MD5 checksum 3ed0ca070aa2fdfc291e433ce042a21b
  Compiled from "SynchronizedTest2.java"
public class new_package.jvm.p46.SynchronizedTest2
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #2.#26         // java/lang/Object."<init>":()V
   #2 = Class              #27            // java/lang/Object
   #3 = Fieldref           #7.#28         // new_package/jvm/p46/SynchronizedTest2.lock:Ljava/lang/Object;
   #4 = Fieldref           #7.#29         // new_package/jvm/p46/SynchronizedTest2.i:I
   #5 = Fieldref           #30.#31        // java/lang/System.out:Ljava/io/PrintStream;
   #6 = Methodref          #32.#33        // java/io/PrintStream.println:(I)V
   #7 = Class              #34            // new_package/jvm/p46/SynchronizedTest2
   #8 = Utf8               lock
   #9 = Utf8               Ljava/lang/Object;
  #10 = Utf8               i
  #11 = Utf8               I
  #12 = Utf8               <init>
  #13 = Utf8               ()V
  #14 = Utf8               Code
  #15 = Utf8               LineNumberTable
  #16 = Utf8               LocalVariableTable
  #17 = Utf8               this
  #18 = Utf8               Lnew_package/jvm/p46/SynchronizedTest2;
  #19 = Utf8               test1
  #20 = Utf8               StackMapTable
  #21 = Class              #34            // new_package/jvm/p46/SynchronizedTest2
  #22 = Class              #27            // java/lang/Object
  #23 = Class              #35            // java/lang/Throwable
  #24 = Utf8               SourceFile
  #25 = Utf8               SynchronizedTest2.java
  #26 = NameAndType        #12:#13        // "<init>":()V
  #27 = Utf8               java/lang/Object
  #28 = NameAndType        #8:#9          // lock:Ljava/lang/Object;
  #29 = NameAndType        #10:#11        // i:I
  #30 = Class              #36            // java/lang/System
  #31 = NameAndType        #37:#38        // out:Ljava/io/PrintStream;
  #32 = Class              #39            // java/io/PrintStream
  #33 = NameAndType        #40:#41        // println:(I)V
  #34 = Utf8               new_package/jvm/p46/SynchronizedTest2
  #35 = Utf8               java/lang/Throwable
  #36 = Utf8               java/lang/System
  #37 = Utf8               out
  #38 = Utf8               Ljava/io/PrintStream;
  #39 = Utf8               java/io/PrintStream
  #40 = Utf8               println
  #41 = Utf8               (I)V
{
  public new_package.jvm.p46.SynchronizedTest2();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=3, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: aload_0
         5: new           #2                  // class java/lang/Object
         8: dup
         9: invokespecial #1                  // Method java/lang/Object."<init>":()V
        12: putfield      #3                  // Field lock:Ljava/lang/Object;
        15: aload_0
        16: iconst_0
        17: putfield      #4                  // Field i:I
        20: return
      LineNumberTable:
        line 8: 0
        line 10: 4
        line 12: 15
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      21     0  this   Lnew_package/jvm/p46/SynchronizedTest2;

  public void test1();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=3, locals=3, args_size=1
         0: aload_0
         1: getfield      #3                  // Field lock:Ljava/lang/Object;
         4: dup
         5: astore_1
         6: monitorenter
         7: aload_0
         8: dup
         9: getfield      #4                  // Field i:I
        12: iconst_1
        13: iadd
        14: putfield      #4                  // Field i:I
        17: aload_1
        18: monitorexit
        19: goto          27
        22: astore_2
        23: aload_1
        24: monitorexit
        25: aload_2
        26: athrow
        27: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;
        30: aload_0
        31: getfield      #4                  // Field i:I
        34: invokevirtual #6                  // Method java/io/PrintStream.println:(I)V
        37: return
      Exception table:
         from    to  target type
             7    19    22   any
            22    25    22   any
      LineNumberTable:
        line 16: 0
        line 17: 7
        line 18: 17
        line 20: 27
        line 21: 37
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      38     0  this   Lnew_package/jvm/p46/SynchronizedTest2;
      StackMapTable: number_of_entries = 2
        frame_type = 255 /* full_frame */
          offset_delta = 22
          locals = [ class new_package/jvm/p46/SynchronizedTest2, class java/lang/Object ]
          stack = [ class java/lang/Throwable ]
        frame_type = 250 /* chop */
          offset_delta = 4
}
SourceFile: "SynchronizedTest2.java"

解析:

  • 存在 monitor 指令
  • 有两个 monitorexit 指令,表示不同情况下的释放锁

类成员变量

package new_package.jvm.p46;

public class Test3 {

    public static Integer num = 333;
}

javap -verbose -p new_package.jvm.p46.Test3

Classfile /Users/kevin/Documents/opensource/gitee/java-read-sources-sample/target/classes/new_package/jvm/p46/Test3.class
  Last modified 2020-6-10; size 453 bytes
  MD5 checksum 556c2f1dbbd64d51ccf97d2c59920873
  Compiled from "Test3.java"
public class new_package.jvm.p46.Test3
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #5.#18         // java/lang/Object."<init>":()V
   #2 = Methodref          #19.#20        // java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
   #3 = Fieldref           #4.#21         // new_package/jvm/p46/Test3.num:Ljava/lang/Integer;
   #4 = Class              #22            // new_package/jvm/p46/Test3
   #5 = Class              #23            // java/lang/Object
   #6 = Utf8               num
   #7 = Utf8               Ljava/lang/Integer;
   #8 = Utf8               <init>
   #9 = Utf8               ()V
  #10 = Utf8               Code
  #11 = Utf8               LineNumberTable
  #12 = Utf8               LocalVariableTable
  #13 = Utf8               this
  #14 = Utf8               Lnew_package/jvm/p46/Test3;
  #15 = Utf8               <clinit>
  #16 = Utf8               SourceFile
  #17 = Utf8               Test3.java
  #18 = NameAndType        #8:#9          // "<init>":()V
  #19 = Class              #24            // java/lang/Integer
  #20 = NameAndType        #25:#26        // valueOf:(I)Ljava/lang/Integer;
  #21 = NameAndType        #6:#7          // num:Ljava/lang/Integer;
  #22 = Utf8               new_package/jvm/p46/Test3
  #23 = Utf8               java/lang/Object
  #24 = Utf8               java/lang/Integer
  #25 = Utf8               valueOf
  #26 = Utf8               (I)Ljava/lang/Integer;
{
  public static java.lang.Integer num;
    descriptor: Ljava/lang/Integer;
    flags: ACC_PUBLIC, ACC_STATIC

  public new_package.jvm.p46.Test3();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 8: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lnew_package/jvm/p46/Test3;

  static {};
    descriptor: ()V
    flags: ACC_STATIC
    Code:
      stack=1, locals=0, args_size=0
         0: sipush        333
         3: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
         6: putstatic     #3                  // Field num:Ljava/lang/Integer;
         9: return
      LineNumberTable:
        line 10: 0
}
SourceFile: "Test3.java"

解析:

  • 存在自动装箱操作(常量池 #2)
  • <clinit> 有静态成员变量时会存在,给静态变量赋初始值
  • 静态变量在 <clinit> 中赋值,成员变量在 <init> 中赋值
  • 静态代码块的内容也是在 <clinit> 中执行;
    • 不管有多少静态代码块,都会合并到一个 <clinit> 中执行;

当静态变量不赋初始值时,不存在 <clinit>:

public class Test3 {

    public static Integer num = null;
}
Classfile /Users/kevin/Documents/opensource/gitee/java-read-sources-sample/target/classes/new_package/jvm/p46/Test3.class
  Last modified 2020-6-10; size 380 bytes
  MD5 checksum 421889337f1b6eb887344e7018dcf555
  Compiled from "Test3.java"
public class new_package.jvm.p46.Test3
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #4.#17         // java/lang/Object."<init>":()V
   #2 = Fieldref           #3.#18         // new_package/jvm/p46/Test3.num:Ljava/lang/Integer;
   #3 = Class              #19            // new_package/jvm/p46/Test3
   #4 = Class              #20            // java/lang/Object
   #5 = Utf8               num
   #6 = Utf8               Ljava/lang/Integer;
   #7 = Utf8               <init>
   #8 = Utf8               ()V
   #9 = Utf8               Code
  #10 = Utf8               LineNumberTable
  #11 = Utf8               LocalVariableTable
  #12 = Utf8               this
  #13 = Utf8               Lnew_package/jvm/p46/Test3;
  #14 = Utf8               <clinit>
  #15 = Utf8               SourceFile
  #16 = Utf8               Test3.java
  #17 = NameAndType        #7:#8          // "<init>":()V
  #18 = NameAndType        #5:#6          // num:Ljava/lang/Integer;
  #19 = Utf8               new_package/jvm/p46/Test3
  #20 = Utf8               java/lang/Object
{
  public static java.lang.Integer num;
    descriptor: Ljava/lang/Integer;
    flags: ACC_PUBLIC, ACC_STATIC

  public new_package.jvm.p46.Test3();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 8: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lnew_package/jvm/p46/Test3;

  static {};
    descriptor: ()V
    flags: ACC_STATIC
    Code:
      stack=1, locals=0, args_size=0
         0: aconst_null
         1: putstatic     #2                  // Field num:Ljava/lang/Integer;
         4: return
      LineNumberTable:
        line 10: 0
}
SourceFile: "Test3.java"

成员变量在 <init> 中赋值

package new_package.jvm.p46;

public class Test4 {

    private int x = 10;

    private String name = "cat";

    public Test4() {
    }

    public Test4(int x) {
        this.x = x;
    }
}

javap -verbose -p new_package.jvm.p46.Test4
Classfile /Users/kevin/Documents/opensource/gitee/java-read-sources-sample/target/classes/new_package/jvm/p46/Test4.class
  Last modified 2020-6-10; size 496 bytes
  MD5 checksum b13c2fd8ac5f933ab8ccb230baa6940b
  Compiled from "Test4.java"
public class new_package.jvm.p46.Test4
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #6.#21         // java/lang/Object."<init>":()V
   #2 = Fieldref           #5.#22         // new_package/jvm/p46/Test4.x:I
   #3 = String             #23            // cat
   #4 = Fieldref           #5.#24         // new_package/jvm/p46/Test4.name:Ljava/lang/String;
   #5 = Class              #25            // new_package/jvm/p46/Test4
   #6 = Class              #26            // java/lang/Object
   #7 = Utf8               x
   #8 = Utf8               I
   #9 = Utf8               name
  #10 = Utf8               Ljava/lang/String;
  #11 = Utf8               <init>
  #12 = Utf8               ()V
  #13 = Utf8               Code
  #14 = Utf8               LineNumberTable
  #15 = Utf8               LocalVariableTable
  #16 = Utf8               this
  #17 = Utf8               Lnew_package/jvm/p46/Test4;
  #18 = Utf8               (I)V
  #19 = Utf8               SourceFile
  #20 = Utf8               Test4.java
  #21 = NameAndType        #11:#12        // "<init>":()V
  #22 = NameAndType        #7:#8          // x:I
  #23 = Utf8               cat
  #24 = NameAndType        #9:#10         // name:Ljava/lang/String;
  #25 = Utf8               new_package/jvm/p46/Test4
  #26 = Utf8               java/lang/Object
{
  private int x;
    descriptor: I
    flags: ACC_PRIVATE

  private java.lang.String name;
    descriptor: Ljava/lang/String;
    flags: ACC_PRIVATE

  public new_package.jvm.p46.Test4();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: aload_0
         5: bipush        10
         7: putfield      #2                  // Field x:I
        10: aload_0
        11: ldc           #3                  // String cat
        13: putfield      #4                  // Field name:Ljava/lang/String;
        16: return
      LineNumberTable:
        line 14: 0
        line 10: 4
        line 12: 10
        line 15: 16
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      17     0  this   Lnew_package/jvm/p46/Test4;

  public new_package.jvm.p46.Test4(int);
    descriptor: (I)V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=2
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: aload_0
         5: bipush        10
         7: putfield      #2                  // Field x:I
        10: aload_0
        11: ldc           #3                  // String cat
        13: putfield      #4                  // Field name:Ljava/lang/String;
        16: aload_0
        17: iload_1
        18: putfield      #2                  // Field x:I
        21: return
      LineNumberTable:
        line 17: 0
        line 10: 4
        line 12: 10
        line 18: 16
        line 19: 21
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      22     0  this   Lnew_package/jvm/p46/Test4;
            0      22     1     x   I
}
SourceFile: "Test4.java"
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值