Analysis on the concept of multithreading tutorial monitor and the principle of synchronized

Posted by jashankoshal on Wed, 05 Jan 2022 18:02:47 +0100

Multithreading tutorial (VII) monitor concept

1, Java object header

java objects are usually composed of two parts in memory, one is the object header, and the other is the member variables in the object.

Take the 32-bit virtual machine as an example, the object header is as follows:

(1) Common object

|--------------------------------------------------------------| 
|						 Object Header (64 bits) 			   |
|------------------------------------|-------------------------|
| 	Mark Word (32 bits) 			 |	 Klass Word (32 bits)  |
|------------------------------------|-------------------------|

The klass word part represents the type of class. It is a pointer to the class corresponding to the object

(2) Array object

|-------------------------------------------------------------------------|
|					    Object Header (96 bits) 						  |
|-----------------------|------------------------|------------------------|
|   Mark Word(32bits) 	|	 Klass Word(32bits)  | 	array length(32bits)  |
|-----------------------|------------------------|------------------------|

(3) The Mark Word structure is

|----------------------------------------------------|--------------------|
| 			Mark Word (32 bits)						 | 		State 		  |
|----------------------------------------------------|--------------------|
| hashcode:25 	| age:4 	| biased_lock:0 	| 01 | 		Normal		  |
|----------------------------------------------------|--------------------|
| thread:23   | epoch:2 | age:4 | biased_lock:1 | 01 |	    Biased 		  |
|----------------------------------------------------|--------------------|
| 		ptr_to_lock_record:30 					| 00 | Lightweight Locked |
|----------------------------------------------------|--------------------|
|		 ptr_to_heavyweight_monitor:30 			| 10 | Heavyweight Locked |
|----------------------------------------------------|--------------------|
| 												| 11 | 	 Marked for GC 	  |
|----------------------------------------------------|--------------------|

64 bit virtual machine Mark Word

|-------------------------------------------------------|-----------------|
| 					Mark Word (64 bits)				 	| 		State 	  |
|-------------------------------------------------------|-----------------|
|unused:25|hashcode:31|unused:1|age:4|biased_lock:0| 01 | 		Normal    |
|-------------------------------------------------------|-----------------|
| thread:54 | epoch:2 |unused:1|age:4|biased_lock:1| 01 | 		Biased    |
|-------------------------------------------------------|-----------------|
| 			ptr_to_lock_record:62 			       | 00 |LightweightLocked|
|-------------------------------------------------------|-----------------|
| 		ptr_to_heavyweight_monitor:62			   | 10 |HeavyweightLocked|
|-------------------------------------------------------|-----------------|
| 												   | 11 |  Marked for GC  |
|-------------------------------------------------------|-----------------|

2, monitor principle

Monitor is translated as monitor or tube pass

Each Java object can be associated with a Monitor object. If you use synchronized to lock the object (heavyweight), the pointer to the Monitor object will be set in the Mark Word of the object header

Bias locks and lightweight locks are not associated with Monitor. The specific principles will be introduced in subsequent chapters (possibly in the lock upgrade chapter)

The Monitor structure is as follows

At the beginning, the Owner in Monitor is null

  1. When Thread-2 executes synchronized(obj), the Owner of the Monitor will be set to Thread-2. There can only be one Owner in the Monitor

  2. In the process of Thread-2 locking, if Thread-3, Thread-4 and Thread-5 also execute synchronized(obj), it will enter the EntryList and the state will change to BLOCKED

  3. Thread-2 executes the contents of the synchronization code block, and then wakes up the waiting threads in the EntryList to compete for the lock. The competition is unfair

  4. In the figure, Thread-0 and Thread-1 in the WaitSet are threads that have obtained locks before, but the conditions are not met to enter the WAITING state. They will be analyzed later when we talk about wait notify

To put it simply, the thread that has obtained the lock in the waitset will release the lock after executing the wait, enter the waitset, and wait for the subsequent thread that has obtained the lock to execute notify or notifyall to activate the thread in the waitset.

This method is often used to wait for the specified thread to produce results before continuing execution.

be careful:

synchronized must enter the monitor of the same object to have the above effect

Objects that are not synchronized are not associated with monitors and do not comply with the above rules

3, synchronized principle

Execute subordinate code

static final Object lock = new Object();
static int counter = 0;
public static void main(String[] args) {
     synchronized (lock) {
     	counter++;
     }
}

Corresponding bytecode:

public static void main(java.lang.String[]);
 descriptor: ([Ljava/lang/String;)V
 flags: ACC_PUBLIC, ACC_STATIC
 Code:
     stack=2, locals=3, args_size=1
         0: getstatic #2 / / < - lock reference (started with synchronized)
         3: dup
         4: astore_1 // lock reference - > slot 1
         5: monitorenter // Set the lock object MarkWord as the Monitor pointer
         6: getstatic #3 // <- i
         9: iconst_1 // Preparation constant 1
         10: iadd // +1
         11: putstatic #3 // -> i
         14: aload_1 // < - lock reference
         15: monitorexit // Reset the lock object MarkWord and wake up the EntryList
         16: goto 24
         19: astore_2 // e -> slot 2 
         20: aload_1 // < - lock reference
         21: monitorexit // Reset the lock object MarkWord and wake up the EntryList
         22: aload_2 // <- slot 2 (e)
         23: athrow // throw e
         24: return
     Exception table:
     	from to target type
     		6 16 19 any
     		19 22 19 any
     LineNumberTable:
         line 8: 0
         line 9: 6
         line 10: 14
         line 11: 24
     LocalVariableTable:
     	Start Length Slot Name Signature
     		0 25 0 args [Ljava/lang/String;
     StackMapTable: number_of_entries = 2
     	frame_type = 255 /* full_frame */
         offset_delta = 19
         locals = [ class "[Ljava/lang/String;", class java/lang/Object ]
         stack = [ class java/lang/Throwable ]
     	frame_type = 250 /* chop */
     		offset_delta = 4

be careful

Method level synchronized is not reflected in bytecode instructions

Topics: Java Back-end