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


    批量

      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>
  • 相关阅读:
    (转) 建立自己的MemberShip数据库
    '??' 语法
    c# 静态构造函数(转)
    ReSharp+VAssistX+VS2003 的个人设置
    支持多种数据类型的ListView排序
    学习笔记
    Java实验报告(实验二)
    Java实验报告(实验一)
    java数组中null和空的区别。
    网页选项卡功能
  • 原文地址:https://www.cnblogs.com/LZXlzmmddtm/p/16188183.html
Copyright © 2020-2023  润新知