Synchronization control instruction of bytecode instruction

catalogue

1, Overview

2, Method level synchronization

3, Method

1, Overview

The java virtual machine supports two synchronization structures:

Method level synchronization and synchronization of an instruction sequence within a method are supported by monitor.

2, Method level synchronization

Method level synchronization: it is implicit, that is, it does not need to be controlled by bytecode instructions. It is implemented in method calls and return operations. The virtual machine can access ACC from the method table structure of the method constant pool_ The synchronized access flag knows whether a method is declared as a synchronous method;

When a method is called, the calling instruction checks the AC of the method_ Whether the synchronized access flag is set.

  • If set, the execution thread will hold the synchronization lock first, and then execute the method. Finally, release the synchronization lock when the method completes (whether it completes normally or abnormally).
  • During method execution, the execution thread holds a synchronization lock, and no other thread can obtain the same lock.
  • If an exception is thrown during the execution of a synchronization method and cannot be handled inside the method, the lock held by the synchronization method will be automatically released when the exception is thrown outside the synchronization method.

give an example:

private int i = 0;

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

Corresponding bytecode:

0 aload_0
 1 dup
 2 getfield #2 <com/wsh/jvm/test/SynchronizedTest.i>
 5 iconst_1
 6 iadd
 7 putfield #2 <com/wsh/jvm/test/SynchronizedTest.i>
10 return

We can see that the bytecode information does not use monitorenter and monitorexit for synchronization area control, just like the bytecode information of ordinary methods.

The method description information is shown in the following figure:

explain:

This code is no different from the ordinary code without synchronization operation. It does not use monitorenter and monitorexit to control the synchronization area. This is because, for the synchronization method, when the virtual machine judges that it is a synchronization method through the access identifier of the method, it will automatically lock before the method call. When the synchronization method is executed, the virtual machine will release the lock regardless of whether the method ends normally or an exception is thrown. Therefore, for the synchronization method, the monitorenter and monitorexit instructions exist implicitly and do not appear directly in the bytecode.

3, Method

Synchronize a sequence of instruction sets: usually represented by synchronized statement blocks in java. The jvm instruction set has two instructions, monitorenter and monitorexit, to support the semantics of the synchronized keyword.

When a thread enters a synchronized code block, it uses the monitorenter instruction to request entry. If the monitor counter of the current object is 0, it will be allowed to enter. If it is 1, it will judge whether the thread holding the current monitor is itself. If it is, it will enter. Otherwise, it will wait until the monitor counter of the object is 0, and it will not be allowed to enter the synchronization block.

When a thread exits a synchronization block, it needs to use the monitorexit declaration to exit. In the Java virtual machine, any object has a monitor associated with it to judge whether the object is locked. When the monitor is held, the object is in the locked state.

When the instructions monitorenter and monitorexit are executed, the object needs to be pushed into the top of the operand stack. Then, the locking and releasing of monitorenter and monitorexit are carried out for the monitor of this object.

The following figure shows how the monitor protects the critical area code from being accessed by multiple threads at the same time. Threads 1, 2 and 3 can enter only after thread 4 leaves the critical area.

give an example:

private int i = 0;

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

private Object obj = new Object();

public void test02() {
    synchronized (obj) {
        i--;
    }
}

View its exception table information:

 

The exception table is described as follows:

  • If an Exception (Exception or its subclass) occurs in lines 7-19, jump to line 22 for Exception handling;
  • If an Exception (Exception or its subclass) occurs in lines 22-25, jump to line 22 for Exception handling: [ensure that the status of the monitor synchronization lock is updated, that is, release the lock]

Take another look at the bytecode information:

0 aload_0   //Load this into the operand stack
 1 getfield #4 <com/wsh/jvm/test/SynchronizedTest. Obj > / / get the obj attribute of the current object and push it into the operand stack
 4 dup   //copy
 5 astore_1   //Save the copied obj to the address with index 1 in the local variable table
 6 monitorenter   //For obj, enter the synchronization monitor
 7 aload_0   //Load this into the operand stack again
 8 dup   //copy
 9 getfield #2 <com/wsh/jvm/test/SynchronizedTest. i> / / get the value 0 of attribute I and push it into the operand stack
12 iconst_1   //Push 1 into the operand stack
13 isub   //Subtract, the result is - 1, and press it into the operand stack
14 putfield #2 <com/wsh/jvm/test/SynchronizedTest. i> / / modify the value of attribute I to - 1
17 aload_1   //Load the variable obj with index 1 in the local variable table into the operand stack
18 monitorexit   //Update monitor status of obj object
19 goto 27 (+8)   //Jump to line 27 and end method execution
##############The following is exception handling################
22 astore_2   
23 aload_1   
24 monitorexit   //Update the monitor status of obj object [it also needs to be unlocked when an exception is thrown]
25 aload_2   
26 athrow   //Throw exception
27 return   //Method return

It can be seen that the bytecode instruction includes monitorenter and monitorexit to control the synchronization area. Before executing the synchronization method, the monitorenter instruction will be executed to obtain the object monitor lock. After the synchronization method is executed, the monitorexit instruction will be executed to release the monitor lock. We can see that there are two monitorexit instructions to ensure that when an exception occurs in the program, The monitor lock can be released.

Keywords: Java

Added by mmponline on Sat, 18 Dec 2021 19:32:23 +0200