前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >偏向锁批量重偏向与批量撤销

偏向锁批量重偏向与批量撤销

作者头像
@阿诚
发布2021-02-04 11:27:58
1.4K0
发布2021-02-04 11:27:58
举报
文章被收录于专栏:Panda诚

批量重偏向:当一个线程创建了大量对象并执行了初始的同步操作,后来另一个线程也来将这些对象作为锁对象进行操作,会导偏向锁重偏向的操作。 批量撤销:在多线程竞争剧烈的情况下,使用偏向锁将会降低效率,于是乎产生了批量撤销机制。 JVM的默认参数值:

  • intx BiasedLockingBulkRebiasThreshold = 20 默认偏向锁批量重偏向阈值
  • intx BiasedLockingBulkRevokeThreshold = 40 默认偏向锁批量撤销阈值

批量重偏向

测试代码:

代码语言:javascript
复制
public static void main(String[] args) throws InterruptedException {
    //延时产生可偏向对象
    Thread.sleep(5000);

    //创造50个偏向线程t1的偏向锁
    List<A> listA = new ArrayList<>();
    Thread t1 = new Thread(() -> {
        for (int i = 0; i < 50; i++) {
            A a = new A();
            synchronized (a) {
                listA.add(a);
            }
        }
        try {
            //为了防止JVM线程复用,在创建完对象后,保持线程t1状态为存活
            Thread.sleep(100000000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    });
    t1.start();

    //睡眠3s钟保证线程t1创建对象完成
    Thread.sleep(3000);
    System.out.println("打印t1线程,list中第20个对象的对象头:");
    System.out.println((ClassLayout.parseInstance(listA.get(19)).toPrintable()));

    //创建线程t2竞争线程t1中已经退出同步块的锁
    Thread t2 = new Thread(() -> {
        //这里面只循环了30次!!!
        for (int i = 0; i < 30; i++) {
            A a = listA.get(i);
            synchronized (a) {
                //分别打印第19次和第20次偏向锁重偏向结果
                if (i == 18 || i == 19) {
                    System.out.println("打印t2线程,第" + (i + 1) + "次偏向结果");
                    System.out.println((ClassLayout.parseInstance(a).toPrintable()));
                }
            }
        }
        try {
            Thread.sleep(10000000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    });
    t2.start();

    Thread.sleep(3000);
    System.out.println("打印list中第11个对象的对象头:");
    System.out.println((ClassLayout.parseInstance(listA.get(10)).toPrintable()));
    System.out.println("打印list中第26个对象的对象头:");
    System.out.println((ClassLayout.parseInstance(listA.get(25)).toPrintable()));
    System.out.println("打印list中第41个对象的对象头:");
    System.out.println((ClassLayout.parseInstance(listA.get(40)).toPrintable()));
}

输出结果:

代码语言:javascript
复制
打印t1线程,list中第20个对象的对象头:
A object internals:
 OFFSET  SIZE      TYPE DESCRIPTION                               VALUE
      0     4           (object header)                           05 c8 35 69 (00000101 11001000 00110101 01101001) (1765132293)
...

这时候所有的对象a都是偏向线程1的,打印出偏向锁没有问题。00000101后三位是101

代码语言:javascript
复制
打印t2线程,第19次偏向结果
A object internals:
 OFFSET  SIZE      TYPE DESCRIPTION                               VALUE
      0     4           (object header)                           f8 e8 47 0a (11111000 11101000 01000111 00001010) (172484856)
...

t2与t1竞争,偏向锁升级为轻量锁,11111000后三位是000

代码语言:javascript
复制
打印t2线程,第20次偏向结果
A object internals:
 OFFSET  SIZE      TYPE DESCRIPTION                               VALUE
      0     4           (object header)                           05 81 34 69 (00000101 10000001 00110100 01101001) (1765048581)
...

前面19个a都偏向锁升级为轻量锁,达到重偏向阈值,第20个a直接重偏向到t2

代码语言:javascript
复制
打印list中第11个对象的对象头:
A object internals:
 OFFSET  SIZE      TYPE DESCRIPTION                               VALUE
      0     4           (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
...

第11个a作为轻量锁走出同步块后,进入无锁状态,00000001后三位是001

代码语言:javascript
复制
打印list中第26个对象的对象头:
A object internals:
 OFFSET  SIZE      TYPE DESCRIPTION                               VALUE
      0     4           (object header)                           05 81 34 69 (00000101 10000001 00110100 01101001) (1765048581)
...

t2竞争了前30个对象a,第0~18个对象a未达到重偏向阈值,是轻量锁,待走出t2同步块后进入无锁状态。第19~29发生重偏向,是偏向锁。

代码语言:javascript
复制
打印list中第41个对象的对象头:
A object internals:
 OFFSET  SIZE      TYPE DESCRIPTION                               VALUE
      0     4           (object header)                           05 c8 35 69 (00000101 11001000 00110101 01101001) (1765132293)
...

第30~49没有发生变化 还是偏向锁

批量撤销

代码语言:javascript
复制
public static void main(String[] args) throws Exception {
    Thread.sleep(5000);
    List<A> listA = new ArrayList<>();

    Thread t1 = new Thread(() -> {
        for (int i = 0; i <50 ; i++) {
            A a = new A();
            synchronized (a){
                listA.add(a);
            }
        }
        try {
            Thread.sleep(100000000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    });
    t1.start();
    Thread.sleep(3000);

    Thread t2 = new Thread(() -> {
        //这里循环了40次。达到了批量撤销的阈值
        for (int i = 0; i < 40; i++) {
            A a =listA.get(i);
            synchronized (a){
            }
        }
        try {
            Thread.sleep(10000000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    });
    t2.start();

    //———————————分割线,前面代码不再赘述——————————————————————————————————————————
    Thread.sleep(3000);
    System.out.println("打印list中第11个对象的对象头:");
    System.out.println((ClassLayout.parseInstance(listA.get(10)).toPrintable()));
    System.out.println("打印list中第26个对象的对象头:");
    System.out.println((ClassLayout.parseInstance(listA.get(25)).toPrintable()));
    System.out.println("打印list中第90个对象的对象头:");
    System.out.println((ClassLayout.parseInstance(listA.get(89)).toPrintable()));

    Thread t3 = new Thread(() -> {
        for (int i = 20; i < 40; i++) {
            A a =listA.get(i);
            synchronized (a){
                if(i==20||i==22){
                    System.out.println("thread3 第"+ i + "次");
                    System.out.println((ClassLayout.parseInstance(a).toPrintable()));
                }
            }
        }
    });
    t3.start();

    Thread.sleep(10000);
    System.out.println("重新输出新实例A");
    System.out.println((ClassLayout.parseInstance(new A()).toPrintable()));
    System.out.println("再次打印list中第50个对象的对象头:");
    System.out.println((ClassLayout.parseInstance(listA.get(49)).toPrintable()));
}
代码语言:javascript
复制
打印list中第11个对象的对象头:
A object internals:
 OFFSET  SIZE      TYPE DESCRIPTION                               VALUE
      0     4           (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
...

第0~19个对象a没有重偏向,走出t2同步块后由轻量锁变无锁001

代码语言:javascript
复制
打印list中第26个对象的对象头:
A object internals:
 OFFSET  SIZE      TYPE DESCRIPTION                               VALUE
      0     4           (object header)                           05 41 10 eb (00000101 01000001 00010000 11101011) (-351256315)
...

第20~39重偏向,仍是偏向锁101

代码语言:javascript
复制
打印list中第50个对象的对象头:
A object internals:
 OFFSET  SIZE      TYPE DESCRIPTION                               VALUE
      0     4           (object header)                           05 38 10 eb (00000101 00111000 00010000 11101011) (-351258619)
...

第40~49仍是偏向t1

代码语言:javascript
复制
thread3 第20次
A object internals:
 OFFSET  SIZE      TYPE DESCRIPTION                               VALUE
      0     4           (object header)                           f8 78 eb 10 (11111000 01111000 11101011 00010000) (283867384)
...
thread3 第22次
A object internals:
 OFFSET  SIZE      TYPE DESCRIPTION                               VALUE
      0     4           (object header)                           f8 78 eb 10 (11111000 01111000 11101011 00010000) (283867384)
...

此时经过t2竞争前40个a,已经到了批量撤销的阈值40,而第20~39已经重偏向过t2,不会再次重偏向,所以升级为轻量锁。(偏向锁重偏向一次之后不可再次重偏向。)

代码语言:javascript
复制
重新输出新实例A
A object internals:
 OFFSET  SIZE      TYPE DESCRIPTION                               VALUE
      0     4           (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
...

打印list中第50个对象的对象头:
A object internals:
 OFFSET  SIZE      TYPE DESCRIPTION                               VALUE
      0     4           (object header)                           05 d8 88 33 (00000101 11011000 10001000 00110011) (864606213)
...

JVM 看到类A已经经历过批量撤销,剥夺了A的新实例对象使用偏向锁的权利;第50个对象a始终没有被t2 t3竞争过,还是偏向t1。(批量重偏向和批量撤销是针对类的优化,和对象无关。)

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-01-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Panda诚 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 批量重偏向
  • 批量撤销
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档