Application and principle analysis of multi-thread-syncronized

Synronized Many developers think that it is a heavyweight lock when they see it. In fact, it is not the case. The JVM defines many states for it. Bias lock -> Lightweight lock -> Weight lock. There are many optimization processes, and the business concept is called lock expansion, lock elimination, and lock revocation. Let's analyze it in detail.

First of all, synchronized essentially acts on the object, modifying the common method lock this object, and modifying the static method lock class object . The following code explains.

@Slf4j
public class SyncronThread03 {
    //以下代码效果一样
    public synchronized void say(){
        log.info("say");
    }
    public  void say1(){
        synchronized (this) {
            log.info("say");
        }
    }

    //以下代码效果一样
    public synchronized static void write(){
        log.info("write");
    }
    public static void write1(){
        synchronized (SyncronThread03.class) {
            log.info("write");
        }
    }
}

Since it acts on the object, it must have a certain relationship with the object. A java object is divided into an object header and an object body. The bottom layer of synchronized is implemented in C, which is executed through the bytecode instructions monitorenter and monitorexit. The synchronized keyword will have a monitor object concept in the operating system, and then associate the monitor object with the mark in the java object header. The monitor object is composed of owner, EntryList, and WaitSet. The functions of the three parts can be given as examples. When multiple threads lock an object at the same time, only one can succeed at a time point. At this time, set the owner as the current thread ID. When other threads try to lock and find that the owner is already held, they will enter blocking (in fact, there is still a process of spinning at the JVM level to try to acquire the lock, and it will block after several attempts), and these threads will enter the EntryList. If there are threads that call the wait method (the lock will be released) during execution, then these threads will enter the WaitSet, and these threads need to be woken up by notify. When the thread holding the lock ends, the owner will be set to null, and then the EntryList thread will be woken up for lock competition. The following is a lock icon.

After understanding the sycronized monitor, then look at the mark in the java object header. The markword is mainly shown in the figure below. It is briefly explained that the first line belongs to normal objects, and the second line belongs to biased locks. The difference is that biased_lock is inconsistent. The third line belongs to the lightweight lock. At this time, the lock pointer in the stack frame + two-digit identifier (00) is stored. The fourth line is a heavyweight lock, which stores the lock pointer + two-digit identifier (10) in the monitor. In the process of locking and unlocking, the java object controls the lock state by changing the information.

 The monitor and markword are introduced separately above, and a practical example is given below to illustrate. Thread T0 now needs to perform a locking operation, and the object of action is object. Before calling synchronized (object), the object is a normal object, the last three digits of the lock ID are 001, and the state is Normal. When calling synchronized (object), the object has two situations. If the biased lock is not disabled, the state is Biased, that is, the last three digits are 101. If the biased lock is disabled, the state is Lightweight Locked. At this time, the object header of the object will store the stack frame lock record and the corresponding pointer, and the last two digits of the lock ID are 00. If it belongs to lock reentry, a new lock record will be added to the current stack frame. The number of reentries is the number of lock records. The illustrations below illustrate.

 The last one is a heavyweight lock. Heavyweight locks are upgraded when lock competition occurs, and the heavyweight at the beginning is not mentioned. Continuing the example above, while T0 is locking, another thread T1 also comes to compete for the object object lock. At this time, the pointer corresponding to the monitor will be stored in the object header of the object, and the last two digits of the lock ID are 10. At this time, the unlocking process T0 is also released from the monitor object to the owner's occupancy. Then revert to the lock-free state. Then other threads compete for the lock.

OK! The above is a theoretical analysis, and the code below actually sees the effect.

Add -XX:BiasedLockingStartupDelay=0 to the VM parameter for biased lock:

import com.example.demostartertest.common.SleepUtils;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.openjdk.jol.info.ClassLayout;

@Slf4j
public class SyncronThread02 {
    public static void main(String[] args) {
        Dog dog = new Dog(); 
        log.info("markword{}",ClassLayout.parseInstance(dog).toPrintable());//原始对象,开了偏向锁,最后位为101
   
        synchronized (dog){
            log.info("markword{}",ClassLayout.parseInstance(dog).toPrintable());//第一次上锁,偏向锁,最后位101
        }

        log.info("markword{}",ClassLayout.parseInstance(dog).toPrintable());
//正常状态,最后位101
    }
}

@Data
class Dog{
    private String name;
}

Lightweight locks (do not open biased locks)

 Heavyweight lock (do not open bias lock)

@Slf4j
public class SyncronThread02 {
    public static void main(String[] args) {
        Dog dog = new Dog();
        log.info("markword{}",ClassLayout.parseInstance(dog).toPrintable());//原始 不偏向 001
        new Thread(()->{
            synchronized (dog){
                log.info("thread markword{}",ClassLayout.parseInstance(dog).toPrintable());//锁竞争,升级重量级 010
                SleepUtils.sleep(2);

            }
        },"t1").start();

        synchronized (dog){
            log.info("markword{}",ClassLayout.parseInstance(dog).toPrintable()); //轻量级 000
        }

        SleepUtils.sleep(3);
        log.info("markword{}",ClassLayout.parseInstance(dog).toPrintable()); //无锁 不偏向 001

    }
}

@Data
class Dog{
    private String name;
}

 Heavyweight lock (open bias lock)

 

Guess you like

Origin blog.csdn.net/weixin_42740540/article/details/124178343