并发编程:批量重偏向、批量撤销

1. 批量重偏向

  • 如果对象虽然被多个线程访问,但没有竞争,这时偏向了线程 T1 的对象仍有机会重新偏向 T2,重偏向会重置对象的 Thread ID;当撤销偏向锁达到阈值 20 次后,jvm 会这样觉得,我是不是偏向错了呢,于是会在给这些对象加锁时重新偏向至t2。因为前19次是轻量,释放之后为无锁不可偏向,但是20次后面的是偏向t2,释放之后依然是偏向t2。
package org.example;

import lombok.extern.slf4j.Slf4j;
import org.example.entity.A;
import org.openjdk.jol.info.ClassLayout;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.LockSupport;

@Slf4j
public class TestInflate {

    static Thread t1;
    static Thread t2;
    static int loopFlag = 20;

    public static void main(String[] args) {
        final List<A> list = new ArrayList<>();
        t1 = new Thread() {
            @Override
            public void run() {
                for (int i = 0; i < loopFlag; i++) {
                    A a = new A();
                    list.add(a);
                    log.debug("加锁前" + i + " " + ClassLayout.parseInstance(a).toPrintable());
                    synchronized (a) {
                        log.debug("加锁中" + i + " " + ClassLayout.parseInstance(a).toPrintable());
                    }
                    log.debug("加锁结束" + i + " " + ClassLayout.parseInstance(a).toPrintable());
                }
                log.debug("============t1 都是偏向锁=============");
                //防止竞争 执行完后叫醒  t2
                LockSupport.unpark(t2);
            }
        };
        t2 = new Thread() {
            @Override
            public void run() {
                //防止竞争 先睡眠t2
                LockSupport.park();
                for (int i = 0; i < loopFlag; i++) {
                    A a = list.get(i);
                    //因为从list当中拿出都是偏向t1
                    log.debug("加锁前" + i + " " + ClassLayout.parseInstance(a).toPrintable());
                    synchronized (a) {
                        //前20撤销偏向t1;然后升级轻量指向t2线程栈当中的锁记录
                        //后面的发送批量偏向t2
                        log.debug("加锁中 " + i + " " + ClassLayout.parseInstance(a).toPrintable());
                    }
                    //因为前20是轻量,释放之后为无锁不可偏向
                    //但是后面的是偏向t2 释放之后依然是偏向t2
                    log.debug("加锁结束" + i + " " + ClassLayout.parseInstance(a).toPrintable());
                }
                log.debug("新产生的对象" + ClassLayout.parseInstance(new  A()).toPrintable());
            }
        };
        t1.start();
        t2.start();

    }

}

  • 关闭偏向延迟,-XX:BiasedLockingStartupDelay=0,查看第19次对象头打印

在这里插入图片描述

  • 查看第20次对象头打印

在这里插入图片描述

2. 批量撤销

  • 当一个偏向锁如果撤销次数到达40的时候就认为这个对象设计的有问题;那么JVM会把这个对象所对应的类所有的对象都撤销偏向锁;并且新实例化的对象也是不可偏向的
  • t1线程创建40个a对象,t2撤销偏向锁40次,t3开始加锁
package org.example;

import lombok.extern.slf4j.Slf4j;
import org.example.entity.A;
import org.openjdk.jol.info.ClassLayout;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.LockSupport;

@Slf4j
public class TestInflate {

    static Thread t1;
    static Thread t2;
    static Thread t3;
    static int loopFlag = 40;

    public static void main(String[] args) {
        final List<A> list = new ArrayList<>();
        t1 = new Thread() {
            @Override
            public void run() {
                for (int i = 0; i < loopFlag; i++) {
                    A a = new A();
                    list.add(a);
                    log.debug("加锁前" + i + " " + ClassLayout.parseInstance(a).toPrintable());
                    synchronized (a) {
                        log.debug("加锁中" + i + " " + ClassLayout.parseInstance(a).toPrintable());
                    }
                    log.debug("加锁结束" + i + " " + ClassLayout.parseInstance(a).toPrintable());
                }
                log.debug("============t1 都是偏向锁=============");
                //防止竞争 执行完后叫醒  t2
                LockSupport.unpark(t2);
            }
        };
        t2 = new Thread() {
            @Override
            public void run() {
                //防止竞争 先睡眠t2
                LockSupport.park();
                for (int i = 0; i < loopFlag; i++) {
                    A a = list.get(i);
                    //因为从list当中拿出都是偏向t1
                    log.debug("加锁前" + i + " " + ClassLayout.parseInstance(a).toPrintable());
                    synchronized (a) {
                        //前20撤销偏向t1;然后升级轻量指向t2线程栈当中的锁记录
                        //后面的发送批量偏向t2
                        log.debug("加锁中 " + i + " " + ClassLayout.parseInstance(a).toPrintable());
                    }
                    //因为前20是轻量,释放之后为无锁不可偏向
                    //但是后面的是偏向t2 释放之后依然是偏向t2
                    log.debug("加锁结束" + i + " " + ClassLayout.parseInstance(a).toPrintable());
                }
                log.debug("新产生的对象" + ClassLayout.parseInstance(new  A()).toPrintable());
                LockSupport.unpark(t3);
            }
        };
        t3 = new Thread() {
            @Override
            public void run() {
                //防止竞争 先睡眠t2
                LockSupport.park();
                for (int i = 0; i < loopFlag; i++) {
                    A a = list.get(i);
                    log.debug("加锁前" + i + " " + ClassLayout.parseInstance(a).toPrintable());
                    synchronized (a) {
                        log.debug("加锁中 " + i + " " + ClassLayout.parseInstance(a).toPrintable());
                    }
                    log.debug("加锁结束" + i + " " + ClassLayout.parseInstance(a).toPrintable());
                }
                log.debug("新产生的对象" + ClassLayout.parseInstance(new  A()).toPrintable());
            }
        };
        t1.start();
        t2.start();
        t3.start();
    }

}

  • 查看t3线程打印

在这里插入图片描述

  • 新创建的a对象也是无所不可偏向的

在这里插入图片描述

  • 6
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值