Synchronized achieve synchronization lock principle

Modified block

    // 关键字在代码块上,锁为括号里面的对象
    public void method2() {
        Object o = new Object();
        synchronized (o) {
            // code
        }
    }
复制代码

Synchronized synchronized block when modified, it is achieved by the monitorenter and monitorexit instructions synchronized. After entering monitorenter instruction, the thread will hold Monitor object after exiting monitorenter instruction, the thread will release the Monitor object.

  // access flags 0x1
  public method2()V
    TRYCATCHBLOCK L0 L1 L2 null
    TRYCATCHBLOCK L2 L3 L2 null
   L4
    LINENUMBER 16 L4
    NEW java/lang/Object
    DUP
    INVOKESPECIAL java/lang/Object.<init> ()V
    ASTORE 1
   L5
    LINENUMBER 17 L5
    ALOAD 1
    DUP
    ASTORE 2
    MONITORENTER
   L0
    LINENUMBER 19 L0
    ALOAD 2
    MONITOREXIT
   L1
    GOTO L6
   L2
   FRAME FULL [com/dragon/learn/leean1/SynchronizedTest java/lang/Object java/lang/Object] [java/lang/Throwable]
    ASTORE 3
    ALOAD 2
    MONITOREXIT
   L3
    ALOAD 3
    ATHROW
   L6
    LINENUMBER 20 L6
   FRAME CHOP 1
    RETURN
   L7
    LOCALVARIABLE this Lcom/dragon/learn/leean1/SynchronizedTest; L4 L7 0
    LOCALVARIABLE o Ljava/lang/Object; L5 L7 1
    MAXSTACK = 2
    MAXLOCALS = 4
}
复制代码

Modification methods

When Synchronized modified synchronization method, and found no monitorenter and monitorexit instruction, but there is a ACC_SYNCHRONIZED flag.

Monitor

Synchronization is based on the JVM to enter and exit the tube (Monitor) object implementation. Each object instance will have a Monitor, Monitor objects can be created together and destruction. Monitor is realized by ObjectMonitor, and ObjectMonitor is implemented in C ++ ObjectMonitor.hpp file as follows:

ObjectMonitor() {
   _header = NULL;
   _count = 0; // 记录个数
   _waiters = 0,
   _recursions = 0;
   _object = NULL;
   _owner = NULL;
   _WaitSet = NULL; // 处于 wait 状态的线程,会被加入到 _WaitSet
   _WaitSetLock = 0 ;
   _Responsible = NULL ;
   _succ = NULL ;
   _cxq = NULL ;
   FreeNext = NULL ;
   _EntryList = NULL ; // 处于等待锁 block 状态的线程,会被加入到该列表
   _SpinFreq = 0 ;
   _SpinClock = 0 ;
   OwnerIsThread = 0 ;
}

复制代码

When multiple threads to access the same block of code, which will first thread into first and EntryList in ContenionList. After thread to acquire the lock by Mutex Lock operating system. If acquired, the corresponding code is executed. If no response is received, then re-enter the ContenionList. If you call the wait method, it will enter WaitSet. When another thread calls notify method will wake up and re-enter EntryList.

Lock promotion optimization

Java object header

Java objects have object header, instance data, padding data of three parts. Wherein the object header consists of a flag field, a pointer type, the length of the array of three parts.

Biased locking

Biased locking is mainly used to optimize multiple applications for the same thread with a lock of competition. When a thread synchronization code or access method again biased locking effect, in a subject in need of head biased locking threads in a thread determines whether the current thread ID. If so, then do not enter the Monitor again went to the competitors.

If there are other threads compete for that resource, then the change will be biased locking revoked. Biased locking revocation need to wait for global security points, to suspend the thread holding the lock. Also check whether the thread is still executing the method, and if so, upgrade the lock, on the contrary, the other thread preemption.

Therefore, under high concurrency scenarios, when a large number of threads simultaneously competing for the same resource lock, the lock will tend to be revoked, after the stop the word occurs, turn biased locking will undoubtedly lead to greater performance overhead, then we can Add closed biased locking JVM parameters to tune the system performance, the following sample code:

Biased locking setting method


-XX:-UseBiasedLocking //关闭偏向锁(默认打开)

-XX:+UseHeavyMonitors  //设置重量级锁
复制代码

Lightweight lock

In addition, when one thread acquires the lock, the lock has been found to be biased locking up, it will go to acquire the lock by CAS way, if the acquisition is successful, a direct replacement for the type of thread ID tag field for the current thread. If the acquisition fails, it will withdraw tend to lock into a lightweight lock.

Lightweight lock is suitable for thread synchronization blocks alternately perform scene, most of the locks do not compete for a long time in the entire synchronization cycle.

Spin locks and lock heavyweight

Lightweight lock CAS to acquire the lock fails, the default will be to get the spin lock by the way. After the spin-lock retry if still failed to grab the lock, the lock will be upgraded to synchronize heavyweight lock, the lock flag is changed to 10. In this state, the lock did not grab the thread will enter the Monitor, after _WaitSet will be blocked in the queue.

Lock eliminate lock coarsening

JIT compiler dynamically compiled synchronized block when the escape analysis techniques will pass. If it is determined that the block will only be one thread access, so the lock will be eliminated.

Lock coarsening the same token, that is, the dynamic compiler JIT compiler, if found several adjacent sync blocks using the same instance of a lock, then the JIT compiler will put a few sync blocks are merged into one large synchronous block, thus avoiding a thread "repeated application, with a lock release" brought about performance overhead.

Reduced lock granularity

This is mainly to optimize the code level.

For example, before JDK8 ConcurrentHashMap, controlled by mechanisms segment.

to sum up

  1. Mark Word detected which is not the current thread ID, and if so, indicates the current thread is biased locking
  2. If not, the CAS will replace the current thread ID to Mark Word, if successful then the current thread gets the lock bias, bias flag is set 1
  3. If it fails, it shows that there is competition, revocation biased locking, upgraded to lightweight lock
  4. CAS current thread using the lock flag to mark Word object header locks the record pointer are replaced, if successful, the current thread to acquire the lock
  5. If it fails, the competition represents another thread lock, the current thread tries to acquire a lock for (;;) by spin
  6. If successful, the spin state is still in a lightweight
  7. If the spin failure, upgraded to heavyweight lock

Guess you like

Origin juejin.im/post/5dac75dce51d45782a479154