JVM synchronized关键字所生成的字节码

一、创建测试类

package com.example.jvm.bytecode;

public class MyTest2 {

    String str = "Welcome";

    private  int x = 5;

    public static  Integer in = 10;

    public static void main(String[] args) {
        MyTest2 myTest2 = new MyTest2();

        myTest2.setX(8);

        in = 20;
    }

    public void setX(int x){
        this.x = x;
    }
  }

 

反编译MyTest2.class文件

D:workspacestudy jvm_demouildclassesjavamaincomexamplejvmytecode>javap -verbose MyTest2.class
Classfile /D:/workspace/study/ jvm_demo/build/classes/java/main/com/example/jvm/bytecode/MyTest2.class
  Last modified 2019-6-26; size 847 bytes
  MD5 checksum d8f82e3e7255d9a738591c52d3a5417b
  Compiled from "MyTest2.java"
public class com.example.jvm.bytecode.MyTest2
  SourceFile: "MyTest2.java"
  minor version: 0
  major version: 51
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #10.#34        //  java/lang/Object."<init>":()V
   #2 = String             #35            //  Welcome
   #3 = Fieldref           #5.#36         //  com/example/jvm/bytecode/MyTest2.str:Ljava/lang/String;
   #4 = Fieldref           #5.#37         //  com/example/jvm/bytecode/MyTest2.x:I
   #5 = Class              #38            //  com/example/jvm/bytecode/MyTest2
   #6 = Methodref          #5.#34         //  com/example/jvm/bytecode/MyTest2."<init>":()V
   #7 = Methodref          #5.#39         //  com/example/jvm/bytecode/MyTest2.setX:(I)V
   #8 = Methodref          #40.#41        //  java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
   #9 = Fieldref           #5.#42         //  com/example/jvm/bytecode/MyTest2.in:Ljava/lang/Integer;
  #10 = Class              #43            //  java/lang/Object
  #11 = Utf8               str
  #12 = Utf8               Ljava/lang/String;
  #13 = Utf8               x
  #14 = Utf8               I
  #15 = Utf8               in
  #16 = Utf8               Ljava/lang/Integer;
  #17 = Utf8               <init>
  #18 = Utf8               ()V
  #19 = Utf8               Code
  #20 = Utf8               LineNumberTable
  #21 = Utf8               LocalVariableTable
  #22 = Utf8               this
  #23 = Utf8               Lcom/example/jvm/bytecode/MyTest2;
  #24 = Utf8               main
  #25 = Utf8               ([Ljava/lang/String;)V
  #26 = Utf8               args
  #27 = Utf8               [Ljava/lang/String;
  #28 = Utf8               myTest2
  #29 = Utf8               setX
  #30 = Utf8               (I)V
  #31 = Utf8               <clinit>
  #32 = Utf8               SourceFile
  #33 = Utf8               MyTest2.java
  #34 = NameAndType        #17:#18        //  "<init>":()V
  #35 = Utf8               Welcome
  #36 = NameAndType        #11:#12        //  str:Ljava/lang/String;
  #37 = NameAndType        #13:#14        //  x:I
  #38 = Utf8               com/example/jvm/bytecode/MyTest2
  #39 = NameAndType        #29:#30        //  setX:(I)V
  #40 = Class              #44            //  java/lang/Integer
  #41 = NameAndType        #45:#46        //  valueOf:(I)Ljava/lang/Integer;
  #42 = NameAndType        #15:#16        //  in:Ljava/lang/Integer;
  #43 = Utf8               java/lang/Object
  #44 = Utf8               java/lang/Integer
  #45 = Utf8               valueOf
  #46 = Utf8               (I)Ljava/lang/Integer;
{
  java.lang.String str;
    flags:

  public static java.lang.Integer in;
    flags: ACC_PUBLIC, ACC_STATIC

  public com.example.jvm.bytecode.MyTest2();
    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: ldc           #2                  // String Welcome
         7: putfield      #3                  // Field str:Ljava/lang/String;
        10: aload_0
        11: iconst_5
        12: putfield      #4                  // Field x:I
        15: return
      LineNumberTable:
        line 3: 0
        line 5: 4
        line 7: 10
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
               0      16     0  this   Lcom/example/jvm/bytecode/MyTest2;

  public static void main(java.lang.String[]);
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=2, args_size=1
         0: new           #5                  // class com/example/jvm/bytecode/MyTest2
         3: dup
         4: invokespecial #6                  // Method "<init>":()V
         7: astore_1
         8: aload_1
         9: bipush        8
        11: invokevirtual #7                  // Method setX:(I)V
        14: bipush        20
        16: invokestatic  #8                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
        19: putstatic     #9                  // Field in:Ljava/lang/Integer;
        22: return
      LineNumberTable:
        line 12: 0
        line 14: 8
        line 16: 14
        line 17: 22
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
               0      23     0  args   [Ljava/lang/String;
               8      15     1 myTest2   Lcom/example/jvm/bytecode/MyTest2;

  public void setX(int);
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=2
         0: aload_0
         1: iload_1
         2: putfield      #4                  // Field x:I
         5: return
      LineNumberTable:
        line 20: 0
        line 21: 5
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
               0       6     0  this   Lcom/example/jvm/bytecode/MyTest2;
               0       6     1     x   I

  static {};
    flags: ACC_STATIC
    Code:
      stack=1, locals=0, args_size=0
         0: bipush        10
         2: invokestatic  #8                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
         5: putstatic     #9                  // Field in:Ljava/lang/Integer;
         8: return
      LineNumberTable:
        line 9: 0
}

  

二、将setX改为private

此时需要使用javap -verbose -p  MyTest2.class才能显示私有方法

D:workspacestudy jvm_demouildclassesjavamaincomexamplejvmytecode>javap -verbose -p  MyTest2.class
Classfile /D:/workspace/study/ jvm_demo/build/classes/java/main/com/example/jvm/bytecode/MyTest2.class
  Last modified 2019-6-27; size 847 bytes
  MD5 checksum f9ed848bb768588b932c395b40c509a8
  Compiled from "MyTest2.java"
public class com.example.jvm.bytecode.MyTest2
  SourceFile: "MyTest2.java"
  minor version: 0
  major version: 51
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #10.#34        //  java/lang/Object."<init>":()V
   #2 = String             #35            //  Welcome
   #3 = Fieldref           #5.#36         //  com/example/jvm/bytecode/MyTest2.str:Ljava/lang/String;
   #4 = Fieldref           #5.#37         //  com/example/jvm/bytecode/MyTest2.x:I
   #5 = Class              #38            //  com/example/jvm/bytecode/MyTest2
   #6 = Methodref          #5.#34         //  com/example/jvm/bytecode/MyTest2."<init>":()V
   #7 = Methodref          #5.#39         //  com/example/jvm/bytecode/MyTest2.setX:(I)V
   #8 = Methodref          #40.#41        //  java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
   #9 = Fieldref           #5.#42         //  com/example/jvm/bytecode/MyTest2.in:Ljava/lang/Integer;
  #10 = Class              #43            //  java/lang/Object
  #11 = Utf8               str
  #12 = Utf8               Ljava/lang/String;
  #13 = Utf8               x
  #14 = Utf8               I
  #15 = Utf8               in
  #16 = Utf8               Ljava/lang/Integer;
  #17 = Utf8               <init>
  #18 = Utf8               ()V
  #19 = Utf8               Code
  #20 = Utf8               LineNumberTable
  #21 = Utf8               LocalVariableTable
  #22 = Utf8               this
  #23 = Utf8               Lcom/example/jvm/bytecode/MyTest2;
  #24 = Utf8               main
  #25 = Utf8               ([Ljava/lang/String;)V
  #26 = Utf8               args
  #27 = Utf8               [Ljava/lang/String;
  #28 = Utf8               myTest2
  #29 = Utf8               setX
  #30 = Utf8               (I)V
  #31 = Utf8               <clinit>
  #32 = Utf8               SourceFile
  #33 = Utf8               MyTest2.java
  #34 = NameAndType        #17:#18        //  "<init>":()V
  #35 = Utf8               Welcome
  #36 = NameAndType        #11:#12        //  str:Ljava/lang/String;
  #37 = NameAndType        #13:#14        //  x:I
  #38 = Utf8               com/example/jvm/bytecode/MyTest2
  #39 = NameAndType        #29:#30        //  setX:(I)V
  #40 = Class              #44            //  java/lang/Integer
  #41 = NameAndType        #45:#46        //  valueOf:(I)Ljava/lang/Integer;
  #42 = NameAndType        #15:#16        //  in:Ljava/lang/Integer;
  #43 = Utf8               java/lang/Object
  #44 = Utf8               java/lang/Integer
  #45 = Utf8               valueOf
  #46 = Utf8               (I)Ljava/lang/Integer;
{
  java.lang.String str;
    flags:

  private int x;
    flags: ACC_PRIVATE

  public static java.lang.Integer in;
    flags: ACC_PUBLIC, ACC_STATIC

  public com.example.jvm.bytecode.MyTest2();
    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: ldc           #2                  // String Welcome
         7: putfield      #3                  // Field str:Ljava/lang/String;
        10: aload_0
        11: iconst_5
        12: putfield      #4                  // Field x:I
        15: return
      LineNumberTable:
        line 3: 0
        line 5: 4
        line 7: 10
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
               0      16     0  this   Lcom/example/jvm/bytecode/MyTest2;

  public static void main(java.lang.String[]);
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=2, args_size=1
         0: new           #5                  // class com/example/jvm/bytecode/MyTest2
         3: dup
         4: invokespecial #6                  // Method "<init>":()V
         7: astore_1
         8: aload_1
         9: bipush        8
        11: invokespecial #7                  // Method setX:(I)V
        14: bipush        20
        16: invokestatic  #8                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
        19: putstatic     #9                  // Field in:Ljava/lang/Integer;
        22: return
      LineNumberTable:
        line 12: 0
        line 14: 8
        line 16: 14
        line 17: 22
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
               0      23     0  args   [Ljava/lang/String;
               8      15     1 myTest2   Lcom/example/jvm/bytecode/MyTest2;

  private void setX(int);
    flags: ACC_PRIVATE
    Code:
      stack=2, locals=2, args_size=2
         0: aload_0
         1: iload_1
         2: putfield      #4                  // Field x:I
         5: return
      LineNumberTable:
        line 20: 0
        line 21: 5
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
               0       6     0  this   Lcom/example/jvm/bytecode/MyTest2;
               0       6     1     x   I

  static {};
    flags: ACC_STATIC
    Code:
      stack=1, locals=0, args_size=0
         0: bipush        10
         2: invokestatic  #8                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
         5: putstatic     #9                  // Field in:Ljava/lang/Integer;
         8: return
      LineNumberTable:
        line 9: 0
}
View Code

三、现在将setX方法增加synchronized 修饰符

private synchronized void setX(int x)
反编译后无synchronized和有synchronized的区别如下图:


四、在类中增加test方法,方法里面使用了synchronize

    private void test(String str){
        synchronized (obj){
            System.out.println("hello world");
        }
    }

  反编译后如下:

 private void test(java.lang.String);
    flags: ACC_PRIVATE
    Code:
      stack=2, locals=4, args_size=2
         0: aload_0
         1: getfield      #6                  // Field obj:Ljava/lang/Object;
         4: dup
         5: astore_2
         6: monitorenter
         7: getstatic     #12                 // Field java/lang/System.out:Ljava/io/PrintStream;
        10: ldc           #13                 // String hello world
        12: invokevirtual #14                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        15: aload_2
        16: monitorexit
        17: goto          25
        20: astore_3
        21: aload_2
        22: monitorexit
        23: aload_3
        24: athrow
        25: return
      Exception table:
         from    to  target type
             7    17    20   any
            20    23    20   any
      LineNumberTable:
        line 26: 0
        line 27: 7
        line 28: 15
        line 29: 25
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
               0      26     0  this   Lcom/example/jvm/bytecode/MyTest2;
               0      26     1   str   Ljava/lang/String;
      StackMapTable: number_of_entries = 2
           frame_type = 255 /* full_frame */
          offset_delta = 20
          locals = [ class com/example/jvm/bytecode/MyTest2, class java/lang/String, class java/lang/Object ]
          stack = [ class java/lang/Throwable ]
           frame_type = 250 /* chop */
          offset_delta = 4

  出现了6: monitorenter和22: monitorexit

给当前MyTest2类所对应的class对象上锁

private synchronized static void test2(){

}

给当前对象上锁

private synchronized void setX(int x){
this.x = x;
}

五、字节码文件分析

最终需要分析的java文件

package com.example.jvm.bytecode;

public class MyTest2 {

    String str = "Welcome";

    private  int x = 5;

    public static  Integer in = 10;

    public static void main(String[] args) {
        MyTest2 myTest2 = new MyTest2();

        myTest2.setX(8);

        in = 20;
    }

    private synchronized void setX(int x){
        this.x = x;
    }

    private void test(String str){
        synchronized (str){
            System.out.println("hello world");
        }
    }

    private synchronized static void test2(){

    }
  }

  然后反编译MyTest2.class

Classfile /D:/workspace/study/ jvm_demo/build/classes/java/main/com/example/jvm/bytecode/MyTest2.class
  Last modified 2019-6-27; size 1265 bytes
  MD5 checksum 1ca3fedabb74af431cc850f3f87b7763
  Compiled from "MyTest2.java"
public class com.example.jvm.bytecode.MyTest2
  SourceFile: "MyTest2.java"
  minor version: 0
  major version: 51
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #13.#45        //  java/lang/Object."<init>":()V
   #2 = String             #46            //  Welcome
   #3 = Fieldref           #5.#47         //  com/example/jvm/bytecode/MyTest2.str:Ljava/lang/String;
   #4 = Fieldref           #5.#48         //  com/example/jvm/bytecode/MyTest2.x:I
   #5 = Class              #49            //  com/example/jvm/bytecode/MyTest2
   #6 = Methodref          #5.#45         //  com/example/jvm/bytecode/MyTest2."<init>":()V
   #7 = Methodref          #5.#50         //  com/example/jvm/bytecode/MyTest2.setX:(I)V
   #8 = Methodref          #51.#52        //  java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
   #9 = Fieldref           #5.#53         //  com/example/jvm/bytecode/MyTest2.in:Ljava/lang/Integer;
  #10 = Fieldref           #54.#55        //  java/lang/System.out:Ljava/io/PrintStream;
  #11 = String             #56            //  hello world
  #12 = Methodref          #57.#58        //  java/io/PrintStream.println:(Ljava/lang/String;)V
  #13 = Class              #59            //  java/lang/Object
  #14 = Utf8               str
  #15 = Utf8               Ljava/lang/String;
  #16 = Utf8               x
  #17 = Utf8               I
  #18 = Utf8               in
  #19 = Utf8               Ljava/lang/Integer;
  #20 = Utf8               <init>
  #21 = Utf8               ()V
  #22 = Utf8               Code
  #23 = Utf8               LineNumberTable
  #24 = Utf8               LocalVariableTable
  #25 = Utf8               this
  #26 = Utf8               Lcom/example/jvm/bytecode/MyTest2;
  #27 = Utf8               main
  #28 = Utf8               ([Ljava/lang/String;)V
  #29 = Utf8               args
  #30 = Utf8               [Ljava/lang/String;
  #31 = Utf8               myTest2
  #32 = Utf8               setX
  #33 = Utf8               (I)V
  #34 = Utf8               test
  #35 = Utf8               (Ljava/lang/String;)V
  #36 = Utf8               StackMapTable
  #37 = Class              #49            //  com/example/jvm/bytecode/MyTest2
  #38 = Class              #60            //  java/lang/String
  #39 = Class              #59            //  java/lang/Object
  #40 = Class              #61            //  java/lang/Throwable
  #41 = Utf8               test2
  #42 = Utf8               <clinit>
  #43 = Utf8               SourceFile
  #44 = Utf8               MyTest2.java
  #45 = NameAndType        #20:#21        //  "<init>":()V
  #46 = Utf8               Welcome
  #47 = NameAndType        #14:#15        //  str:Ljava/lang/String;
  #48 = NameAndType        #16:#17        //  x:I
  #49 = Utf8               com/example/jvm/bytecode/MyTest2
  #50 = NameAndType        #32:#33        //  setX:(I)V
  #51 = Class              #62            //  java/lang/Integer
  #52 = NameAndType        #63:#64        //  valueOf:(I)Ljava/lang/Integer;
  #53 = NameAndType        #18:#19        //  in:Ljava/lang/Integer;
  #54 = Class              #65            //  java/lang/System
  #55 = NameAndType        #66:#67        //  out:Ljava/io/PrintStream;
  #56 = Utf8               hello world
  #57 = Class              #68            //  java/io/PrintStream
  #58 = NameAndType        #69:#35        //  println:(Ljava/lang/String;)V
  #59 = Utf8               java/lang/Object
  #60 = Utf8               java/lang/String
  #61 = Utf8               java/lang/Throwable
  #62 = Utf8               java/lang/Integer
  #63 = Utf8               valueOf
  #64 = Utf8               (I)Ljava/lang/Integer;
  #65 = Utf8               java/lang/System
  #66 = Utf8               out
  #67 = Utf8               Ljava/io/PrintStream;
  #68 = Utf8               java/io/PrintStream
  #69 = Utf8               println
{
  java.lang.String str;
    flags:

  private int x;
    flags: ACC_PRIVATE

  public static java.lang.Integer in;
    flags: ACC_PUBLIC, ACC_STATIC

  public com.example.jvm.bytecode.MyTest2();
    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: ldc           #2                  // String Welcome
         7: putfield      #3                  // Field str:Ljava/lang/String;
        10: aload_0
        11: iconst_5
        12: putfield      #4                  // Field x:I
        15: return
      LineNumberTable:
        line 3: 0
        line 5: 4
        line 7: 10
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
               0      16     0  this   Lcom/example/jvm/bytecode/MyTest2;

  public static void main(java.lang.String[]);
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=2, args_size=1
         0: new           #5                  // class com/example/jvm/bytecode/MyTest2
         3: dup
         4: invokespecial #6                  // Method "<init>":()V
         7: astore_1
         8: aload_1
         9: bipush        8
        11: invokespecial #7                  // Method setX:(I)V
        14: bipush        20
        16: invokestatic  #8                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
        19: putstatic     #9                  // Field in:Ljava/lang/Integer;
        22: return
      LineNumberTable:
        line 12: 0
        line 14: 8
        line 16: 14
        line 17: 22
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
               0      23     0  args   [Ljava/lang/String;
               8      15     1 myTest2   Lcom/example/jvm/bytecode/MyTest2;

  private synchronized void setX(int);
    flags: ACC_PRIVATE, ACC_SYNCHRONIZED
    Code:
      stack=2, locals=2, args_size=2
         0: aload_0
         1: iload_1
         2: putfield      #4                  // Field x:I
         5: return
      LineNumberTable:
        line 20: 0
        line 21: 5
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
               0       6     0  this   Lcom/example/jvm/bytecode/MyTest2;
               0       6     1     x   I

  private void test(java.lang.String);
    flags: ACC_PRIVATE
    Code:
      stack=2, locals=4, args_size=2
         0: aload_1
         1: dup
         2: astore_2
         3: monitorenter
         4: getstatic     #10                 // Field java/lang/System.out:Ljava/io/PrintStream;
         7: ldc           #11                 // String hello world
         9: invokevirtual #12                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        12: aload_2
        13: monitorexit
        14: goto          22
        17: astore_3
        18: aload_2
        19: monitorexit
        20: aload_3
        21: athrow
        22: return
      Exception table:
         from    to  target type
             4    14    17   any
            17    20    17   any
      LineNumberTable:
        line 24: 0
        line 25: 4
        line 26: 12
        line 27: 22
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
               0      23     0  this   Lcom/example/jvm/bytecode/MyTest2;
               0      23     1   str   Ljava/lang/String;
      StackMapTable: number_of_entries = 2
           frame_type = 255 /* full_frame */
          offset_delta = 17
          locals = [ class com/example/jvm/bytecode/MyTest2, class java/lang/String, class java/lang/Object ]
          stack = [ class java/lang/Throwable ]
           frame_type = 250 /* chop */
          offset_delta = 4


  private static synchronized void test2();
    flags: ACC_PRIVATE, ACC_STATIC, ACC_SYNCHRONIZED
    Code:
      stack=0, locals=0, args_size=0
         0: return
      LineNumberTable:
        line 31: 0

  static {};
    flags: ACC_STATIC
    Code:
      stack=1, locals=0, args_size=0
         0: bipush        10
         2: invokestatic  #8                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
         5: putstatic     #9                  // Field in:Ljava/lang/Integer;
         8: return
      LineNumberTable:
        line 9: 0
}

然后打开WinHex打开MyTest2.class 文件

原文地址:https://www.cnblogs.com/linlf03/p/11097179.html