Synchronized修饰方法和代码块在底层的一些区别

文章目录

    • 修饰代码块
    • 修饰实例方法
    • 修饰静态方法
    • 总结

修饰代码块

上例子:

public class SyncCodeBlock {
    public int i;

    public void syncTask(){
        //同步代码库
        synchronized (this){
            i++;
        }
    }
}

使用javac编译,使用javap查看字节码:


$javac SyncCodeBlock.java
$javap -v -c -s -l SyncCodeBlock.class
Classfile /Users/mac/IdeaProjects/multiThread/src/main/java/ThreadBasic/Synchronized/SyncCodeBlock.class
  Last modified 2020-6-26; size 427 bytes
  MD5 checksum 46c58b50c71e6579e6e3d8b903ac2680
  Compiled from "SyncCodeBlock.java"
public class ThreadBasic.Synchronized.SyncCodeBlock
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #4.#18         // java/lang/Object."":()V
   #2 = Fieldref           #3.#19         // ThreadBasic/Synchronized/SyncCodeBlock.i:I
   #3 = Class              #20            // ThreadBasic/Synchronized/SyncCodeBlock
   #4 = Class              #21            // java/lang/Object
   #5 = Utf8               i
   #6 = Utf8               I
   #7 = Utf8               
   #8 = Utf8               ()V
   #9 = Utf8               Code
  #10 = Utf8               LineNumberTable
  #11 = Utf8               syncTask
  #12 = Utf8               StackMapTable
  #13 = Class              #20            // ThreadBasic/Synchronized/SyncCodeBlock
  #14 = Class              #21            // java/lang/Object
  #15 = Class              #22            // java/lang/Throwable
  #16 = Utf8               SourceFile
  #17 = Utf8               SyncCodeBlock.java
  #18 = NameAndType        #7:#8          // "":()V
  #19 = NameAndType        #5:#6          // i:I
  #20 = Utf8               ThreadBasic/Synchronized/SyncCodeBlock
  #21 = Utf8               java/lang/Object
  #22 = Utf8               java/lang/Throwable
{
  public int i;
    descriptor: I
    flags: ACC_PUBLIC

  public ThreadBasic.Synchronized.SyncCodeBlock();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."":()V
         4: return
      LineNumberTable:
        line 3: 0

  public void syncTask();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=3, locals=3, args_size=1
         0: aload_0
         1: dup
         2: astore_1
         3: monitorenter
         4: aload_0
         5: dup
         6: getfield      #2                  // Field i:I
         9: iconst_1
        10: iadd
        11: putfield      #2                  // Field i:I
        14: aload_1
        15: monitorexit
        16: goto          24
        19: astore_2
        20: aload_1
        21: monitorexit
        22: aload_2
        23: athrow
        24: return
      Exception table:
         from    to  target type
             4    16    19   any
            19    22    19   any
      LineNumberTable:
        line 9: 0
        line 10: 4
        line 11: 14
        line 12: 24
      StackMapTable: number_of_entries = 2
        frame_type = 255 /* full_frame */
          offset_delta = 19
          locals = [ class ThreadBasic/Synchronized/SyncCodeBlock, class java/lang/Object ]
          stack = [ class java/lang/Throwable ]
        frame_type = 250 /* chop */
          offset_delta = 4
}
SourceFile: "SyncCodeBlock.java"

JVM 是通过进入、退出对象监视器( Monitor )来实现对代码块的同步的。

修饰实例方法

public class SyncInstance implements  Runnable{
        static int i = 0;

        public synchronized void increase() {
            i++;
        }

        @Override
        public void run() {
            for (int j = 0; j < 5; j++) {
                increase();
            }
        }

        public static void main(String[] args) throws InterruptedException {
            //new新实例
            Thread t1 = new Thread(new SyncInstance());
            //new新实例
            t1.start();
            //join含义:当前线程A等待thread线程终止之后才能从thread.join()返回
            t1.join();
        }
}

查看其字节码:

$javac SyncInstance.java
$javap -v -c -s -l SyncInstance.class
Classfile /Users/mac/IdeaProjects/multiThread/src/main/java/ThreadBasic/Synchronized/SyncInstance.class
  Last modified 2020-6-26; size 769 bytes
  MD5 checksum 4bc0bc765b64da5799760cf7a04b01cc
  Compiled from "SyncInstance.java"
public class ThreadBasic.Synchronized.SyncInstance implements java.lang.Runnable
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #10.#28        // java/lang/Object."":()V
   #2 = Fieldref           #5.#29         // ThreadBasic/Synchronized/SyncInstance.i:I
   #3 = Methodref          #5.#30         // ThreadBasic/Synchronized/SyncInstance.increase:()V
   #4 = Class              #31            // java/lang/Thread
   #5 = Class              #32            // ThreadBasic/Synchronized/SyncInstance
   #6 = Methodref          #5.#28         // ThreadBasic/Synchronized/SyncInstance."":()V
   #7 = Methodref          #4.#33         // java/lang/Thread."":(Ljava/lang/Runnable;)V
   #8 = Methodref          #4.#34         // java/lang/Thread.start:()V
   #9 = Methodref          #4.#35         // java/lang/Thread.join:()V
  #10 = Class              #36            // java/lang/Object
  #11 = Class              #37            // java/lang/Runnable
  #12 = Utf8               i
  #13 = Utf8               I
  #14 = Utf8               
  #15 = Utf8               ()V
  #16 = Utf8               Code
  #17 = Utf8               LineNumberTable
  #18 = Utf8               increase
  #19 = Utf8               run
  #20 = Utf8               StackMapTable
  #21 = Utf8               main
  #22 = Utf8               ([Ljava/lang/String;)V
  #23 = Utf8               Exceptions
  #24 = Class              #38            // java/lang/InterruptedException
  #25 = Utf8               
  #26 = Utf8               SourceFile
  #27 = Utf8               SyncInstance.java
  #28 = NameAndType        #14:#15        // "":()V
  #29 = NameAndType        #12:#13        // i:I
  #30 = NameAndType        #18:#15        // increase:()V
  #31 = Utf8               java/lang/Thread
  #32 = Utf8               ThreadBasic/Synchronized/SyncInstance
  #33 = NameAndType        #14:#39        // "":(Ljava/lang/Runnable;)V
  #34 = NameAndType        #40:#15        // start:()V
  #35 = NameAndType        #41:#15        // join:()V
  #36 = Utf8               java/lang/Object
  #37 = Utf8               java/lang/Runnable
  #38 = Utf8               java/lang/InterruptedException
  #39 = Utf8               (Ljava/lang/Runnable;)V
  #40 = Utf8               start
  #41 = Utf8               join
{
  static int i;
    descriptor: I
    flags: ACC_STATIC

  public ThreadBasic.Synchronized.SyncInstance();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."":()V
         4: return
      LineNumberTable:
        line 3: 0

  public synchronized void increase();
    descriptor: ()V
    flags: ACC_PUBLIC, ACC_SYNCHRONIZED
    Code:
      stack=2, locals=1, args_size=1
         0: getstatic     #2                  // Field i:I
         3: iconst_1
         4: iadd
         5: putstatic     #2                  // Field i:I
         8: return
      LineNumberTable:
        line 7: 0
        line 8: 8

  public void run();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=1
         0: iconst_0
         1: istore_1
         2: iload_1
         3: iconst_5
         4: if_icmpge     17
         7: aload_0
         8: invokevirtual #3                  // Method increase:()V
        11: iinc          1, 1
        14: goto          2
        17: return
      LineNumberTable:
        line 12: 0
        line 13: 7
        line 12: 11
        line 15: 17
      StackMapTable: number_of_entries = 2
        frame_type = 252 /* append */
          offset_delta = 2
          locals = [ int ]
        frame_type = 250 /* chop */
          offset_delta = 14

  public static void main(java.lang.String[]) throws java.lang.InterruptedException;
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=4, locals=2, args_size=1
         0: new           #4                  // class java/lang/Thread
         3: dup
         4: new           #5                  // class ThreadBasic/Synchronized/SyncInstance
         7: dup
         8: invokespecial #6                  // Method "":()V
        11: invokespecial #7                  // Method java/lang/Thread."":(Ljava/lang/Runnable;)V
        14: astore_1
        15: aload_1
        16: invokevirtual #8                  // Method java/lang/Thread.start:()V
        19: aload_1
        20: invokevirtual #9                  // Method java/lang/Thread.join:()V
        23: return
      LineNumberTable:
        line 19: 0
        line 21: 15
        line 23: 19
        line 24: 23
    Exceptions:
      throws java.lang.InterruptedException

  static {};
    descriptor: ()V
    flags: ACC_STATIC
    Code:
      stack=1, locals=0, args_size=0
         0: iconst_0
         1: putstatic     #2                  // Field i:I
         4: return
      LineNumberTable:
        line 4: 0
}
SourceFile: "SyncInstance.java"

synchronized修饰的实例方法并没有monitorenter指令和monitorexit指令,取而代之的是ACC_SYNCHRONIZED标识,该标识指明了该方法是一个同步方法,JVM通过该ACC_SYNCHRONIZED访问标志来辨别一个方法是否声明为同步方法,从而执行相应的同步调用;

修饰静态方法

package ThreadBasic.Synchronized;

public class SynStatic implements Runnable {
    static int i = 0;

    public static synchronized void increase() {
        i++;
    }

    @Override
    public void run() {
        for (int j = 0; j < 5; j++) {
            increase();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        //new新实例
        Thread t1 = new Thread(new SynStatic());
        //new新实例
        t1.start();
        //join含义:当前线程A等待thread线程终止之后才能从thread.join()返回
        t1.join();
    }
}


查看其字节码:

$javac SynStatic.java
$javap -c -v -s -l SynStatic.class
Classfile /Users/mac/IdeaProjects/multiThread/src/main/java/ThreadBasic/Synchronized/SynStatic.class
  Last modified 2020-6-26; size 762 bytes
  MD5 checksum f66c06958c4b1a7b9e84d47933cc6dda
  Compiled from "SynStatic.java"
public class ThreadBasic.Synchronized.SynStatic implements java.lang.Runnable
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #10.#28        // java/lang/Object."":()V
   #2 = Fieldref           #5.#29         // ThreadBasic/Synchronized/SynStatic.i:I
   #3 = Methodref          #5.#30         // ThreadBasic/Synchronized/SynStatic.increase:()V
   #4 = Class              #31            // java/lang/Thread
   #5 = Class              #32            // ThreadBasic/Synchronized/SynStatic
   #6 = Methodref          #5.#28         // ThreadBasic/Synchronized/SynStatic."":()V
   #7 = Methodref          #4.#33         // java/lang/Thread."":(Ljava/lang/Runnable;)V
   #8 = Methodref          #4.#34         // java/lang/Thread.start:()V
   #9 = Methodref          #4.#35         // java/lang/Thread.join:()V
  #10 = Class              #36            // java/lang/Object
  #11 = Class              #37            // java/lang/Runnable
  #12 = Utf8               i
  #13 = Utf8               I
  #14 = Utf8               
  #15 = Utf8               ()V
  #16 = Utf8               Code
  #17 = Utf8               LineNumberTable
  #18 = Utf8               increase
  #19 = Utf8               run
  #20 = Utf8               StackMapTable
  #21 = Utf8               main
  #22 = Utf8               ([Ljava/lang/String;)V
  #23 = Utf8               Exceptions
  #24 = Class              #38            // java/lang/InterruptedException
  #25 = Utf8               
  #26 = Utf8               SourceFile
  #27 = Utf8               SynStatic.java
  #28 = NameAndType        #14:#15        // "":()V
  #29 = NameAndType        #12:#13        // i:I
  #30 = NameAndType        #18:#15        // increase:()V
  #31 = Utf8               java/lang/Thread
  #32 = Utf8               ThreadBasic/Synchronized/SynStatic
  #33 = NameAndType        #14:#39        // "":(Ljava/lang/Runnable;)V
  #34 = NameAndType        #40:#15        // start:()V
  #35 = NameAndType        #41:#15        // join:()V
  #36 = Utf8               java/lang/Object
  #37 = Utf8               java/lang/Runnable
  #38 = Utf8               java/lang/InterruptedException
  #39 = Utf8               (Ljava/lang/Runnable;)V
  #40 = Utf8               start
  #41 = Utf8               join
{
  static int i;
    descriptor: I
    flags: ACC_STATIC

  public ThreadBasic.Synchronized.SynStatic();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."":()V
         4: return
      LineNumberTable:
        line 3: 0

  public static synchronized void increase();
    descriptor: ()V
    flags: ACC_PUBLIC, ACC_STATIC, ACC_SYNCHRONIZED
    Code:
      stack=2, locals=0, args_size=0
         0: getstatic     #2                  // Field i:I
         3: iconst_1
         4: iadd
         5: putstatic     #2                  // Field i:I
         8: return
      LineNumberTable:
        line 7: 0
        line 8: 8

  public void run();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=1
         0: iconst_0
         1: istore_1
         2: iload_1
         3: iconst_5
         4: if_icmpge     16
         7: invokestatic  #3                  // Method increase:()V
        10: iinc          1, 1
        13: goto          2
        16: return
      LineNumberTable:
        line 12: 0
        line 13: 7
        line 12: 10
        line 15: 16
      StackMapTable: number_of_entries = 2
        frame_type = 252 /* append */
          offset_delta = 2
          locals = [ int ]
        frame_type = 250 /* chop */
          offset_delta = 13

  public static void main(java.lang.String[]) throws java.lang.InterruptedException;
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=4, locals=2, args_size=1
         0: new           #4                  // class java/lang/Thread
         3: dup
         4: new           #5                  // class ThreadBasic/Synchronized/SynStatic
         7: dup
         8: invokespecial #6                  // Method "":()V
        11: invokespecial #7                  // Method java/lang/Thread."":(Ljava/lang/Runnable;)V
        14: astore_1
        15: aload_1
        16: invokevirtual #8                  // Method java/lang/Thread.start:()V
        19: aload_1
        20: invokevirtual #9                  // Method java/lang/Thread.join:()V
        23: return
      LineNumberTable:
        line 19: 0
        line 21: 15
        line 23: 19
        line 24: 23
    Exceptions:
      throws java.lang.InterruptedException

  static {};
    descriptor: ()V
    flags: ACC_STATIC
    Code:
      stack=1, locals=0, args_size=0
         0: iconst_0
         1: putstatic     #2                  // Field i:I
         4: return
      LineNumberTable:
        line 4: 0
}
SourceFile: "SynStatic.java"

synchronized修饰的静态方法也没有monitorenter指令和monitorexit指令,取得代之的是ACC_SYNCHRONIZED标识;

总结

synchronized修饰代码块的时候:
同步语句块的实现使用的是monitorenter 和 monitorexit 指令,其中monitorenter指令指向同步代码块的开始位置,monitorexit指令则指明同步代码块的结束位置;
synchronized修饰方法的时候:
synchronized修饰的方法并没有monitorenter指令和monitorexit指令,取而代之的是ACC_SYNCHRONIZED标识,该标识指明了该方法是一个同步方法,JVM通过该ACC_SYNCHRONIZED访问标志来辨别一个方法是否声明为同步方法,从而执行相应的同步调用。

你可能感兴趣的:(java进击之路)