关于偏向锁的批量重偏向与批量消除

批量

  synchronized中的偏向锁是将线程id标记到markword中以占用锁

  1.撤销

  当对象调用hashcode时,会把hashcode存到markdown,这个hashcode是延迟更新的,只有调用的时候才会填入,所以这个时候如果有偏向锁,hashcode会将偏向锁挤走,也就是末尾bit置为001正常状态。

  当线程1被标记了偏向后,线程2也调用了锁,两个线程之间不存在竞争关系,则会发生偏向撤销,也就是锁会升级成轻量级锁,状态从101->000->001.

  2.批量重偏向。

  当频繁出现撤销时(初始阈值为20),jvm会认为该类的锁是否确实标量了线程1.从而会运行其重偏量到其他线程,状态也从001->101,即线程2的偏向状态。

  实现步骤:

  修改线程2的锁列表范围0-40,前0-19现象为撤销101->000->001,后20-40的现象为重偏向101->101->101

  之后所有从线程1修改太到其他线程的偏向锁都会重新偏向。

  3.批量撤销。

  当出现频繁撤销时(阈值为40),jvm会认为该类确实不应该偏向线程1,则会将该类的所有对象全部不可偏向,包括新生成的锁对象。

  实验步骤:

  修改线程2的锁列表范围0-40,其中0-19现象为撤销101->000->001,后20-40的现象为重偏向101->101->101,线程3的锁列表范围为20-50,其中20-40的锁偏向为从线程2的修改偏向,会计为偏向撤销101->000->001,升级到轻量级锁,40-50则会触发批量撤销条件自动取消偏向状态也为撤销101->000->001。

  所以,40触发条件的撤销为从线程1转为线程2的20个撤销+线程2转为线程3的20个撤销。

  代碼:

package com.lizhenxin.java0422.b3;

import com.lizhenxin.java0422.util.Sleeper;
import lombok.extern.slf4j.Slf4j;
import org.openjdk.jol.info.ClassLayout;

import java.util.ArrayList;
import java.util.List;
import java.util.Vector;

/**
 * @author lizhenxin
 * @create 2022-04-24-18:05
 */
@Slf4j
public class Test4 {

    public static void main(String[] args) throws Exception {
//        Sleeper.sleep(1);
        int forCount = 100;
        Vector<Dog> list = new Vector<Dog>();
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < forCount; i++) {
                Dog d = new Dog();
                list.add(d);
                synchronized (d) {
                    log.debug(i + "\t" + MyClassLayout.printMarkDown(d));
                }
            }
            synchronized (list) {
                list.notify();
            }
        }, "t1");
        t1.start();

        Thread t2 = new Thread(() -> {
            synchronized (list) {
                try {
                    list.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            log.debug("===============> ");
            for (int i = 0; i < 40; i++) {
                Dog d = list.get(i);
                log.debug(i + "\t" + MyClassLayout.printMarkDown(d));
                synchronized (d) {
                    log.debug(i + "\t" + MyClassLayout.printMarkDown(d));
                }
                log.debug(i + "\t" + MyClassLayout.printMarkDown(d));
            }
            synchronized (MyClassLayout.class) {
                MyClassLayout.class.notify();
            }
        }, "t2");
        t2.start();
        Thread t3 = new Thread(() -> {
            synchronized (MyClassLayout.class) {
                try {
                    MyClassLayout.class.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            log.debug("===============> ");
            for (int i = 20; i < 50; i++) {
                Dog d = list.get(i);
                log.debug(i + "\t" + MyClassLayout.printMarkDown(d));
                synchronized (d) {
                    log.debug(i + "\t" + MyClassLayout.printMarkDown(d));
                }
                log.debug(i + "\t" + MyClassLayout.printMarkDown(d));
            }
            synchronized (lock.class) {
                lock.class.notify();
            }
        }, "t3");
        t3.start();
        Thread t4 = new Thread(() -> {
            synchronized (lock.class) {
                try {
                    lock.class.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            log.debug("===============> ");
            for (int i = 20; i < forCount; i++) {
                Dog d = list.get(i);
                log.debug(i + "\t" + MyClassLayout.printMarkDown(d));
                synchronized (d) {
                    log.debug(i + "\t" + MyClassLayout.printMarkDown(d));
                }
                log.debug(i + "\t" + MyClassLayout.printMarkDown(d));
            }
        }, "t4");
        t4.start();
        t4.join();
        log.debug(MyClassLayout.printMarkDown(new Dog()));
    }
}


class Dog{

}

class MyClassLayout{


    static String printMarkDown(Object instance){
        String[] split = ClassLayout.parseInstance(instance).toPrintable().split("\\r\\n");
        String s = split[2];
        return s.substring(60,s.length());
    }
}

class lock{

}

  maven:

        <dependency>
            <groupId>org.openjdk.jol</groupId>
            <artifactId>jol-core</artifactId>
            <version>0.9</version>
        </dependency>

 

posted on 2022-04-24 22:56  一只萌萌哒的提莫  阅读(473)  评论(0编辑  收藏  举报