On the realization of the principle of synchronized

Foreword

Synchronized heavyweight lock in Java, when I had just Java multi-threaded programming, I only know about its implementation and monitor, but the relationship between synchronized and monitor, and monitor the nature of what is, I did not try to understand, choosing instead to simply skip. In recent times, due to the actual need, I put this question turned out, Google a lot of information, the whole process of realization finally understand, in order to prevent forgotten, it became sort of this blog. In this blog, I will be the class file as a breakthrough, trying to explain the realization of the principle of Synchronized.

From talking about java code disassembly

It is easy to think, from the behavior of a program to understand the implementation principle of synchronized. However, the source code level, does not appear that realization of the principle of synchronized. Lock difference and do not lock, it seems just have not been synchronized modification. Better to look into more on the bottom of the compilation, see if you can find a breakthrough. javap is provided by the official * .class file splitter, it helps us get the assembly code * .class files. Refer to the specific usage here . Then I would use the command javap * .class files to disassemble. Preparation of documents Test.java:

public class Test {

    private int i = 0;

    public void addI_1(){
        synchronized (this){
            i++;
        }
    }

    public synchronized  void addI_2(){
        i++;
    }
}
复制代码

Generate class files, and get results Test.class disassembled:

javac Test.java
javap -v Test.class
复制代码
Classfile /Users/zhangkunwei/Desktop/Test.class
  Last modified Jul 13, 2018; size 453 bytes
  MD5 checksum ada74ec8231c64230d6ae133fee5dd16
  Compiled from "Test.java"
  ... ...
  public void addI_1();
    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
  ... ...
    public synchronized void addI_2();
    descriptor: ()V
    flags: ACC_PUBLIC, ACC_SYNCHRONIZED
    Code:
      stack=3, locals=1, args_size=1
         0: aload_0
         1: dup
         2: getfield      #2                  // Field i:I
         5: iconst_1
         6: iadd
         7: putfield      #2                  // Field i:I
        10: return
   ... ...
复制代码

By disassemble result, we can see:

  • Will execute when entering the synchronized statement block modified the monitorenter , will be executed when leaving monitorexit .
  • Compared to the synchronized modified sentence block, a modified method is not synchronized instructions monitorenter and the monitorexit , and more ACC_SYNCHRONIZED flags in flag. monitorenter and monitorexit instructions what to do? The principle statement block synchronization and synchronization method What is the difference? Never failing to check the documents to see if the official interpretation of the document.

monitorenter

Description The objectref must be of type reference.

Each object is associated with a monitor. A monitor is locked if and only if it has an owner. The thread > that executes monitorenter attempts to gain ownership of the monitor associated with objectref, as > > follows:

  • If the entry count of the monitor associated with objectref is zero, the thread enters the monitor > and sets its entry count to one. The thread is then the owner of the monitor.

  • If the thread already owns the monitor associated with objectref, it reenters the monitor, incrementing its entry count.

  • If another thread already owns the monitor associated with objectref, the thread blocks until the monitor's entry count is zero, then tries again to gain ownership.

Notes

  • A monitorenter instruction may be used with one or more monitorexit instructions (§monitorexit) to implement a synchronized statement in the Java programming language (§3.14). The monitorenter and monitorexit instructions are not used in the implementation of synchronized methods, although they can be used to provide equivalent locking semantics. Monitor entry on invocation of a synchronized method, and monitor exit on its return, are handled implicitly by the Java Virtual Machine's method invocation and return instructions, as if monitorenter and monitorexit were used.

Simple translation this: instruction monitorenter operation must be a reference to an object, and the type of reference. Each object will have a monitor associated with them, if and only if the monitor is (other (threads) objects) hold time, monitor will be locked. Its implementation detail is that when a thread tries to hold an object's monitor when:

  • If the object's monitor in the entry count == 0, then the entry count is set to 1, and let the thread monitor holder.
  • If the thread is already the object's monitor holder, then re-enter the monitor , and make entry count increment once.
  • If another thread already holds the object's monitor , the thread will be blocked until the monitor in the entry COUNT == 0, and then try to hold back. Note: the monitorenter must be more than one monitorexit used in conjunction to achieve synchronization statement block in Java. The synchronization method is not the case: the synchronization method does not use monitorenter and monitorexit to achieve. When the synchronization method is called, Monitor intervene; when synchronization method return, Monitor quits. These two operations, are to be JVM implicit handle, as if these two instructions are executed the same.

monitorexit

Description

  • The objectref must be of type reference.

  • The thread that executes monitorexit must be the owner of the monitor associated with the instance referenced by objectref.

  • The thread decrements the entry count of the monitor associated with objectref. If as a result the value of the entry count is zero, the thread exits the monitor and is no longer its owner. Other threads that are blocking to enter the monitor are allowed to attempt to do so.

Simple translation this: instruction monitorenter operation must be a reference to an object, and the type of reference. and:

  • Execution monitorexit thread must monitor holders.
  • Execution monitorexit thread so that the monitor of the entry count is decremented once. If the last entry COUNT == 0, this thread is no longer monitor holder, it means that other threads can be blocked attempts to hold monitor

Based on the above information, it has been explained above questions:

  1. monitorenter and monitorexit is doing what? monitorenter can "lock" object. When a thread gets monitor the lock, and other requests access to the shared memory space thread can not gain access is blocked; monitorexit able to "unlock" the object, wake up by not getting access to the shared memory space is blocked thread.

  2. Why a monitorenter and more monitorexit correspondence is one to many, rather than one to one? The many reasons, in order to ensure: executed monitorenter instruction, there will be a back monitorexit instruction is executed. In the above example, normal program execution when leaving the implementation of a sync block of statements monitorexit ; program during the Runtime throws Exception or Error, then perform a second monitorexit to exit sync block.

  3. Why sync block of statements and disassembled code synchronization method is slightly different? Sync block of statements is used monitorenter and monitorexit implemented; is synchronized JVM implicit processing effects monitorenter and monitorexit same. And, flags synchronization methods are not the same, one more ACC_SYNCHRONIZED signs, the signs are telling the JVM : This method is a synchronous method, can refer here .

Monitor

In the previous section, we easily come to a conclusion: synchronized implementation and monitor relevant. monitor what is it? As can be seen from the description of the document, Monitor similar to the operating system mutex concept: different objects access to the shared memory space are mutually exclusive. In the JVM ( Hotspot is available in), Monitor is ObjectMonitor achieved, the main data is structured as follows:

ObjectMonitor() {
    _header       = NULL;
    _count        = 0;
    _waiters      = 0,
    _recursions   = 0;
    _object       = NULL;
    _owner        = NULL;   //指向当前monitor的持有者 
    _WaitSet      = NULL;   //持有monitor后,调用的wait()的线程集合
    _WaitSetLock  = 0 ;
    _Responsible  = NULL ;
    _succ         = NULL ;
    _cxq          = NULL ;
    FreeNext      = NULL ;
    _EntryList    = NULL ;  //尝试持有monitor失败后被阻塞的线程集合
    _SpinFreq     = 0 ;
    _SpinClock    = 0 ;
    OwnerIsThread = 0 ;
    _previous_owner_tid = 0;
}
复制代码

As can be seen, we can

  • By modifying _owner to indicate monitor the owner of the lock;
  • Gets a collection of threads due to failure to acquire the lock is blocked by reading _EntryList;
  • To obtain a set of threads give up after obtaining lock lock by reading _WaitSet.

Here, the basic realization of the principle of synchronized been straightened, but there is an unresolved question: how do you know the thread monitor addresses? Thread only know its address, to be able to access it before you can contact the above analysis. The answer is the monitor address in Java object header.

Java object header

In Java, the composition of each object has a Java object header. Head by an object, we can get information about the object. This is the data structure of the Java object header (32-bit virtual machine):

Wherein the Mark Word, which is a variable data structure, i.e., its data structure is the circumstantial. The following is the corresponding lock state, Mark Word data structure (the 32-bit virtual machine):
a heavyweight lock is synchronized, so heavyweight lock state corresponds to FIG. Wherein a field is: a pointer points to the heavyweight lock, occupy a total of 25 + 4 + 1 = 30bit, its content is a reference to the object associated monitor address. Threads can be obtained by Java object header Mark Word field monitor address in order to get the lock.

Back to the original question

What is the realization of the principle of synchronized? From the above analysis, the answer is already obvious. When multiple threads accessing a shared memory space together, these threads may be synchronized by locking the object in the object header in accordance Mark Word field to access the object associated Monitor , and try to get. When a thread successfully acquired the monitor , the other competing monitor tenure thread will be blocked, and enter EntryList. When the thread is finished, release the lock contention due to monitor failure blocked thread will be woken up, then repeat the above steps.

Written in the last

I discovered that in fact most of the answers can be obtained from the document, so after experiencing problems still have to try to find the answer from the document. I limited, and if there is an error this article, look to correct me, thank you ~

Guess you like

Origin juejin.im/post/5d499d2cf265da03eb13b1ef