[Java] Talk about the synchronized keyword again (principle)

In the first introduction to the synchronized keyword, the usage and characteristics of synchronized were introduced, and then let's take a look at the principle of synchronized.

Lock strategy implemented by synchronized

1. It is both an optimistic lock and a pessimistic lock;
2. It is both a lightweight lock and a heavyweight lock;
3. It is an ordinary mutual exclusion lock;
4. It is both a spin lock and a pending lock;
5. It is a reentrant lock;
6 . is an unfair lock.
Lightweight locks are implemented based on spin locks, and heavyweight locks are implemented based on pending locks .

The principle of synchronized

lock escalation

From the previous study of lock strategies, we can know that synchronized may use different lock strategies in different periods.
Lock-free state --> biased lock --> lightweight lock --> heavyweight lock lock
-free : no thread to compete for lock resources;
biased lock : not really locked, but only recorded in the object header of the lock A mark (recording the thread to which the lock belongs). If no other thread participates in the competition for the lock, then the locking operation will not be actually performed, thereby reducing the program overhead. Once other threads are really involved in the competition, then cancel the biased lock state, Enter the lightweight lock state.;
Lightweight lock : CAS in user mode;
Heavyweight lock : Kernel mode lock, implemented by instructions.
With the intensity of lock competition between threads, the state of the lock will continue to escalate.

public class Demo02_Layout_Synchronized {
    
    
    // 定义一些变量
    private int count;
    private long count1 = 200;
    private String hello = "";
    // 定义一个对象变量
    private TestLayout test001 = new TestLayout();

    public static void main(String[] args) throws InterruptedException {
    
    
        // 创建一个对象的实例
        Object obj = new Object();
        // 打印实例布局
        System.out.println("=== 任意Object对象布局,起初为无锁状态");
        System.out.println(ClassLayout.parseInstance(obj).toPrintable());

        System.out.println("=== 延时4S开启偏向锁");
        // 延时4S开启偏向锁
        Thread.sleep(5000);
        // 创建本类的实例
        Demo02_Layout_Synchronized monitor = new Demo02_Layout_Synchronized();
        // 打印实例布局,注意查看锁状态为偏向锁
        System.out.println("=== 打印实例布局,注意查看锁状态为偏向锁");
        System.out.println(ClassLayout.parseInstance(monitor).toPrintable());

        System.out.println("==== synchronized加锁");
        // 加锁后观察加锁信息
        synchronized (monitor) {
    
    
            System.out.println("==== 第一层synchronized加锁后");
            System.out.println(ClassLayout.parseInstance(monitor).toPrintable());
            // 锁重入,查看锁信息
            synchronized (monitor) {
    
    
                System.out.println("==== 第二层synchronized加锁后,锁重入");
                System.out.println(ClassLayout.parseInstance(monitor).toPrintable());
            }
            // 释放里层的锁
            System.out.println("==== 释放内层锁后");
            System.out.println(ClassLayout.parseInstance(monitor).toPrintable());
        }
        // 释放所有锁之后
        System.out.println("==== 释放 所有锁");
        System.out.println(ClassLayout.parseInstance(monitor).toPrintable());

        System.out.println("==== 多个线程参与锁竞争,观察锁状态");
        Thread thread1 = new Thread(() -> {
    
    
            synchronized (monitor) {
    
    
                System.out.println("=== 在线程A 中获取锁,参与锁竞争,当前只有线程A 竞争锁,轻度锁竞争");
                System.out.println(ClassLayout.parseInstance(monitor).toPrintable());
            }
        });
        thread1.start();

        // 休眠一会,不与线程A 激烈竞争
        Thread.sleep(100);
        Thread thread2 = new Thread(() -> {
    
    
            synchronized (monitor) {
    
    
                System.out.println("=== 在线程B 中获取锁,与其他线程进行锁竞争");
                System.out.println(ClassLayout.parseInstance(monitor).toPrintable());
            }
        });
        thread2.start();

        // 不休眠直接竞争锁,产生激烈竞争
        System.out.println("==== 不休眠直接竞争锁,产生激烈竞争");
        synchronized (monitor) {
    
    
            // 加锁后的类对象
            System.out.println("==== 与线程B 产生激烈的锁竞争,观察锁状态为fat lock");
            System.out.println(ClassLayout.parseInstance(monitor).toPrintable());
        }
        // 休眠一会释放锁后
        Thread.sleep(100);
        System.out.println("==== 释放锁后");
        System.out.println(ClassLayout.parseInstance(monitor).toPrintable());

        System.out.println("===========================================================================================");
        System.out.println("===========================================================================================");
        System.out.println("===========================================================================================");
        System.out.println("===========================================================================================");
        System.out.println("===========================================================================================");
        System.out.println("===========================================================================================");

        // 调用hashCode后才保存hashCode的值
        monitor.hashCode();
        // 调用hashCode后观察现象
        System.out.println("==== 调用hashCode后查看hashCode的值");
        System.out.println(ClassLayout.parseInstance(monitor).toPrintable());
        // 强制执行垃圾回收
        System.gc();
        // 观察GC计数
        System.out.println("==== 调用GC后查看age的值");
        System.out.println(ClassLayout.parseInstance(monitor).toPrintable());
        // 打印类布局,注意调用的方法不同
        System.out.println("==== 查看类布局");
        System.out.println(ClassLayout.parseClass(Demo02_Layout_Synchronized.class).toPrintable());
        // 打印类对象布局
        System.out.println("==== 查看类对象布局");
        System.out.println(ClassLayout.parseInstance(Demo02_Layout_Synchronized.class).toPrintable());



    }
}

class TestLayout {
    
    

}

1. When the program is just started, the created object cannot be used as a bias lock.
insert image description here2. The objects created during the running of the program are biasable.
insert image description here
3. Add bias lock. At this time, the thread information that currently acquires the lock is recorded.
insert image description here
4. Although the lock is released, as long as there is no contention, the lock is always in a biased state and stored in the object header.
insert image description here
5. When a thread competes with the main thread, it will be upgraded to a lightweight lock.
insert image description here
6. Continue to create threads to participate in lock competition and it will be upgraded to a heavyweight lock.
insert image description here

lock elimination

When writing code, programmers add synchronized to ensure thread safety. If there are only read operations and no write operations in the synchronized code block, the JVM will think that this code block does not need to be locked, and it will be optimized when running from the JVM. This phenomenon is called lock elimination, filtering out invalid synchronized, Thereby improving efficiency. The JVM will only optimize when it is 100% sure .

lock coarsening

There are four lock competitions in the execution of a business logic. In the case of ensuring that the program is executed correctly, the JVM will make optimizations, only add a lock once, and then release it after the entire logic is executed, thereby improving efficiency.
insert image description here


Keep going~
insert image description here

Guess you like

Origin blog.csdn.net/qq_43243800/article/details/131215577