Some differences between Synchronized decorating method and code block at the bottom

Article catalog

Decorated code block

The above example:

public class SyncCodeBlock {
    public int i;

    public void syncTask(){
        //Sync codebase
        synchronized (this){
            i++;
        }
    }
}

Compile with javac and view bytecode with 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."<init>":()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               <init>
   #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          // "<init>":()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."<init>":()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"

The JVM synchronizes code blocks by entering and exiting the object Monitor.

Modify instance method

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 new instance
            Thread t1 = new Thread(new SyncInstance());
            //New new instance
            t1.start();
            //Join meaning: the current thread A waits for the thread to terminate before it can start thread.join() return
            t1.join();
        }
}

To view its bytecode:

$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."<init>":()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."<init>":()V
   #7 = Methodref          #4.#33         // java/lang/Thread."<init>":(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               <init>
  #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               <clinit>
  #26 = Utf8               SourceFile
  #27 = Utf8               SyncInstance.java
  #28 = NameAndType        #14:#15        // "<init>":()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        // "<init>":(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."<init>":()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 "<init>":()V
        11: invokespecial #7                  // Method java/lang/Thread."<init>":(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"

The synchronized decorated instance method does not have the monitorenter and monitorexit instructions, but acc_ The synchronized ID indicates that the method is a synchronization method, and the JVM uses the ACC_ The synchronized access flag is used to identify whether a method is declared as a synchronous method, so as to execute the corresponding synchronous call;

Modifying static methods

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 new instance
        Thread t1 = new Thread(new SynStatic());
        //New new instance
        t1.start();
        //Join meaning: the current thread A waits for the thread to terminate before starting thread.join() return
        t1.join();
    }
}


To view its bytecode:

$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."<init>":()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."<init>":()V
   #7 = Methodref          #4.#33         // java/lang/Thread."<init>":(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               <init>
  #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               <clinit>
  #26 = Utf8               SourceFile
  #27 = Utf8               SynStatic.java
  #28 = NameAndType        #14:#15        // "<init>":()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        // "<init>":(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."<init>":()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 "<init>":()V
        11: invokespecial #7                  // Method java/lang/Thread."<init>":(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"

The static method modified by synchronized does not have the monitorenter instruction and monitorexit instruction. Instead, ACC is used to get_ Synchronized identification;

summary

When synchronized decorates a code block:
The implementation of synchronous statement block uses the monitorenter and monitorexit instructions, in which the monitorenter instruction points to the start position of synchronous code block and the monitorexit instruction indicates the end position of synchronous code block;
When the synchronized modifier is used:
Instead of the monitorenter and monitorexit instructions, the synchronized decorated method is acc_ The synchronized ID indicates that the method is a synchronization method, and the JVM uses the ACC_ The synchronized access flag is used to identify whether a method is declared as a synchronized method, so as to execute the corresponding synchronized call.


Tags: Java Mac jvm

Posted on Sat, 27 Jun 2020 02:14:36 -0400 by bobby4