Interview~Synchronized and lock upgrade


Talk about Synchronized/ Talk about Synchronized lock upgrade

Internal implementation of Markword

There are big differences in the implementation of synchronized methods and code blocks in bytecode, but the internal implementation is still based on the MarkWord of the object header .


Before jdk5heavyweight lock

synchronized only has heavyweight locks. Synchronized is implemented through a monitor lock (Monitor) inside the object .

However, the essence of the monitor lock depends on the mutex lock of the underlying operating system .

Moreover, the operating system needs to switch from user mode to kernel mode to implement switching between threads , which is very costly .

Transitions between states take a relatively long time, which is why Synchronized is inefficient .

Therefore, this kind of lock implemented by Mutex Lock that relies on the operating system is called a "heavyweight lock".


JDK6 startsbiased locks, lightweight locks

Optimize synchronized and add adaptive CAS spin, lock elimination, lock expansion, 偏向锁and轻量级锁 other optimization strategies.

Locks can be upgraded from biased locks to lightweight locks, and then to heavyweight locks . But the upgrade of the lock is one-way, that is to say, it can only be upgraded from low to high.

In JDK 1.6, biased locks and lightweight locks are enabled by default . Biased locks can be disabled through -XX:-UseBiasedLocking.


bias lock

The introduction of biased locks is because the author of HotSpot discovered through research and practice that

In most cases, locks not only do not compete with multiple threads, but are always acquired multiple times by the same thread . In order to make it more cost-effective for threads to acquire locks, biased locks are introduced.

After the thread holds the bias lock, subsequent access to the synchronized code block does not require acquiring or releasing the lock .

Biased locking is a mechanism used when a single thread executes a code block . If it is in a multi-threaded concurrent environment (that is, thread A has not finished executing the synchronized code block, and thread B has initiated a lock application ), it will definitely be converted into a lightweight lock application. Level lock or heavyweight lock .

"Biased" means that biased locks assume that only the first thread that applies for the lock will use the lock in the future (no thread will apply for the lock again) .

Therefore, you only need to record the owner in Mark Word CAS (essentially also updated, but the initial value is empty),

If the recording is successful, the biased lock acquisition is successful, and the recorded lock status is a biased lock. In the future, if the current thread is equal to the owner, it can directly obtain the lock at zero cost;

Otherwise, it means that there are other threads competing and the lock will expand to a lightweight lock.


Lightweight lock

The purpose of introducing lightweight locks is actually to avoid the use of heavyweight locks.

CAS spin avoids blocking and waking up threads in a short period of time, because blocking and waking up threads correspond to the switching between user mode and kernel mode of the operating system , thereby saving resources and improving program running performance.


Therefore, various locks are not substitutes for each other, but different choices in different scenarios.

  • Biased lock: There is no actual competition, and only the first thread to apply for the lock will use the lock in the future.
  • Lightweight lock: no actual competition, multiple threads use the lock alternately; short-term lock competition is allowed.
  • Heavyweight lock: there is actual competition and fierce competition

Summary of the synchronized lock upgrade process: In one sentence, spin first, and then block if it fails.



Other necessary knowledge

CAS spin

// 执行一个无意义的循环,目的就是等代机会去竞争到锁
while(true){
    
    
	//空的
	//一个:每次自旋的时间
	//另外一个:自旋的次数
}

The role of spin:

It avoids blocking and waking up threads in a short period of time, because the blocking and waking up of threads correspond to the switching between user mode and kernel mode of the operating system , thereby saving resources and improving program running performance.


Lock information storage

The lock information is stored in the Mark word of the object header. The Mark word stores the corresponding lock information according to the lock status.

synchronized and lock upgrade: The Mark Word in the object header is reused and the lock upgrade strategy is based on the different lock flags .

  • Biased lock: MarkWord stores the biased thread ID ;

  • Lightweight lock: MarkWord stores a pointer to the Lock Record in the thread ;

  • Weight lock: MarkWord stores a pointer to the monitor object in ;


lock status

Unlocked state

Bias lock state

lightweight lock state

Heavyweight lock status


Advantages and Disadvantages of Various Locks


Alibaba Development Manual

[Mandatory] When concurrency is high, synchronous calls should be considered 锁的性能损耗.

If you can use lock-free data structures, don't use locks ; if you can lock blocks, don't lock the entire method body ; if you can use object locks, don't use class locks .

Note: Try to keep the workload of the locked code block as small as possible and avoid calling RPC methods in the locked code block.


Common interview questions

1. You mentioned the optimization of synchronized. Can you elaborate on the difference between biased locks and lightweight locks?

Different CAS times, whether to actively release the lock

A lightweight lock requires at least one CAS each time it applies for and releases a lock , while a biased lock only requires one CAS during initialization .


Biased locks only favor the first accessing thread . When this thread (thread A) accesses the synchronization block for the first time, CAS will be used to update the ThreadID of the object header to the id of the biased thread . Subsequent accesses only need to compare whether the threadId is the same, and no CAS operation is required. And the thread in this direction will not automatically lock unless there are threads to compete.

When the second thread (thread B) comes to visit, he does not know that the first thread already exists. So this second thread thought it was favored, and it also wanted to use CAS to initialize the ThreadID of the object header like the biased thread, but found that it failed.

It means that the object lock has been occupied by other threads, and thread competition has occurred .

Check whether the thread that originally held the object lock is still alive .

If it hangs , you can change the object to a lock-free state and then redirect it to a new thread.

If the thread is still alive, check whether the thread is executing the code in the synchronized code block . If so, upgrade to a lightweight lock and perform CAS competition lock.

CAS for lightweight locks needs to be executed every time you apply for a lock .



2. How do you usually use the synchronized keyword?

(1) Modify instance method : lock the current object instance

synchronized void method() {
    
    
 //业务代码
}

(2) Modify the static method : that is, lock the current class

synchronized void staic method() {
    
    
 //业务代码
}

(3) Modify code blocks

synchronized(this|object|xx.class) {
    
    
 //业务代码
}

Double retrieval in singleton mode also uses singletons

/* 双重检验锁  */
public class Singleton{
     
     
 private Singleton(){
     
     }//构造器私有化,防止new,导致多个实例
 private static volatile Singleton singleton;
 public static Singleton getInstance(){
     
     //向外暴露一个静态的公共方法  getInstance
     //第一层检查
     if(singleton == null){
     
     
         //同步代码块
         synchronized (Singleton.class){
     
     
              //第二层检查
             if(singleton == null) {
     
     
                 singleton = new Singleton();
             }
         }

     }
     return singleton;
 }
}




If this article is helpful to you, please remember to give Yile a like, thank you!

Guess you like

Origin blog.csdn.net/weixin_45630258/article/details/127079913