Lock principle: bias lock, lightweight lock, weight lock

 Every object in java can be used as a lock. There are four levels of locks, which are divided into lock-free, biased lock, lightweight lock, and heavy-weight lock according to the order of magnitude. Each object is lock-free at the beginning. As threads compete for locks, the more intense the lock level, the higher the lock level, and the lock can only be upgraded but not downgraded.

First, the java object header

 The implementation mechanism of the lock is closely related to the java object header, and all the information of the lock is recorded in the java object header. Use 2 words (1 word = 32bit = 4 baye in 32-bit JVM) to store the object header, if it is an array type, use 3 words to store (also need to store the length of the array). The object header records the hash value, GC age, lock status, thread owner, and pointer to class metadata.

The structure of the Java object header
Structure of Mark Word in different lock states (under 32 bits)

2. Bias lock

 In the actual application running process, it is found that "the lock is always held by the same thread, and competition rarely occurs", that is to say, the lock is always owned by the first thread that occupies it, and this thread is the bias thread of the lock.

 Then just record the bias thread ID when the lock is first owned. In this way, the biased thread has been holding the lock until the competition occurs and the lock is released. After each synchronization, check whether the biased thread ID of the lock is consistent with the current thread ID. If they are consistent, enter the synchronization directly, and exit the synchronization. There is no need to go to CAS to update the object header every time the lock is unlocked. If the inconsistency means that there is a competition, the lock It is not always biased towards the same thread. At this time, the lock needs to be expanded into a lightweight lock to ensure fair competition between threads.

1. Lock


Biased lock locking occurs when the biased thread enters the synchronized block for the first time, and the CAS atomic operation tries to update the Mark Word of the object (the biased lock flag is "1", which records the ID of the biased thread).

2. Revoke bias lock

 When there is another thread competing for the lock, the biased lock can no longer be used, and it must be expanded to a lightweight lock.
Competing threads attempt to CAS to update object headers and fail, and will wait until a global safepoint (at which time no code will be executed) to revoke the biased lock.
The process of revoking a biased lock
The process of revoking a biased lock

3. Lightweight lock

 The difference between lightweight lock and bias lock is:

  1. The lightweight lock needs to release the lock every time it exits the synchronized block, while the biased lock releases the lock when the competition occurs
  2. Every time you enter and exit a synchronized block, you need CAS to update the object header
  3. When contention for a lightweight lock fails, spin tries to preempt the lock

 It can be seen that lightweight locks are suitable for use in competitive situations, and their spin locks can ensure fast response speed, but spin operations will occupy the CPU, so some operations with long computing time are not suitable for lightweight locks.

1. Lock

 The locking process is similar to that of biased locking. CAS also modifies the object header, but the content of the modification is different.

  1. Save pointer to current thread in MarkWord
  2. Modify the lock flag to "00"

The reason for using CAS operation is that you don't want to add synchronization to locking and unlocking

 If the object is in a lock-free state (the biased lock flag is "0" and the lock flag is "01"), a lock record space (Lock Record) will be opened in the thread's stack, and a copy of Mark Word will be copied to the Lock Record. , called Displaced Mark Word, saves the pointer (owner) of the object head in the Lock Record.
Next, CAS updates MarkWord, pointing MarkWord to the current thread, and owner to MarkWord. If it fails, it means that another thread competes for the lock, and the lock needs to be expanded into a lightweight lock.

Stack and MarkWord state before CAS operation
Stack and MarkWord status after CAS operation

2. Unlock

 Use the CAS operation to lock into a lock-free state (the bias lock bit is "0", and the lock flag bit is "01"). If the CAS operation fails, there is a competition, and the lock has expanded into a heavyweight lock, which needs to be released at this time. lock (the pointer bit of the thread holding the heavyweight lock is "0", and the lock flag bit is "10") and wake up the thread of the heavyweight lock.

3. Inflate for heavyweight locks

 When the competing thread fails to occupy the lightweight lock for many times, the lightweight lock will expand into a heavyweight lock, the heavyweight thread pointer points to the competing thread, and the competing thread will also block, waiting for the lightweight thread to release the lock and wake it up .
Inflate into heavyweight lock

Three, heavyweight lock

 The locking and unlocking process of heavyweight locks is similar to that of lightweight locks. The difference is: after the competition fails, the thread is blocked. After the lock is released, the blocked thread is awakened, and the spin lock is not used, so it will not consume the CPU so much, so the heavyweight lock Locks are suitable when synchronized blocks take a long time to execute.

4. Reference

  1. The Art of Java Concurrent Programming
  2. "Lightweight Lock and Bias Lock"
  3. "Three kinds of locks under Synchronized: Bias lock light weight lock weight lock understanding"
  4. "The expansion process and optimization of JAVA locks"

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326446813&siteId=291194637