0
点赞
收藏
分享

微信扫一扫

sychronized底层原理

小铺有酒一两不够 2022-03-11 阅读 159
java面试

一探究竟:反编译

三种使用场景,示例代码;

public class SynchronizePrincipe {

    public synchronized static void fun1(){}
    public synchronized void fun2(){}
    public void fun3() {
        synchronized (this){}
    }
}

通过javap -c -v命令反编译后(部分代码);

 public static synchronized void fun1();
    descriptor: ()V
    // 看这里
    flags: ACC_PUBLIC, ACC_STATIC, ACC_SYNCHRONIZED

  public synchronized void fun2();
    descriptor: ()V
    // 看这里
    flags: ACC_PUBLIC, ACC_SYNCHRONIZED

  public void fun3();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=3, args_size=1
         0: aload_0
         1: dup
         2: astore_1
         // 看这里
         3: monitorenter
         4: aload_1
         // 看这里
         5: monitorexit
         6: goto          14
         9: astore_2
        10: aload_1
         // 看这里
        11: monitorexit
  • 修饰方法:ACC_SYNCHRONIZED标识,会隐式调用到下面两个方法;
  • 修饰代码块:一个monitorenter,两个monitorexit,避免异常未释放锁;

总结:sychronized本质就是对monitor的争夺,在持有重量级锁对象头中,存储了monitor的指针。

基础知识:对象结构

Java对象由三个部分组成;

  1. 对象头:对象年龄,锁标志,Class类型指针和数组长度(可选);
  2. 实例数据:真正存储的有效数据,例如当前的成员变量,包括父类;
  3. 对齐填充:HotSpot VM规定对象起始地址为8字节的整数倍,不够则需要填充;

Mark Word

重中之重:对象锁

锁类型

  • non-biasable 无锁且不可偏向
  • biasable 无锁可偏向
  • biased 偏向锁
  • thin lock 轻量级锁
  • fat lock 重量级锁

rebias & revoke

  • bulk rebias(批量重偏向):如果已经偏向t1线程的对象,在t2线程申请锁时撤销偏向后升级为轻量级锁的对象数量达到一定值(20),后续的申请会批量重偏向到t2线程;
  • bulk revoke(批量撤销):在单位时间(25s)内某种Class的对象撤销偏向的次数达到一定值(40),JVM认定该Class竞争激烈,撤销所有关联对象的偏向锁,且新实例也是不可偏向的;

对象初始化

申请加锁

证据第一:动手试试

JVM参数

-XX:+UseBiasedLocking 启用偏向锁,默认启用
-XX:+PrintFlagsFinal 打印JVM所有参数
-XX:BiasedLockingStartupDelay=4000 偏向锁启用延迟时间,默认4秒
-XX:BiasedLockingBulkRebiasThreshold=20 批量重偏向阈值,默认20
-XX:BiasedLockingBulkRevokeThreshold=40 批量撤销阈值,默认40
-XX:BiasedLockingDecayTime=25000

添加依赖

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

统一打印对象头方法;

public static void print(Object flag, Object object) {
    String str = ClassLayout.parseInstance(object).toPrintable();
    System.out.println(flag + ".......................................");
    System.out.println(str);
}

锁升级

public static void main(String[] args) {
    Object init = new Object();
    // non-biasable 不可偏向
    print("init before", init);
    synchronized (init) {
        // thin lock 轻量级锁
        print("init sync", init);
    }
    sleep(4000);
    Object object = new Object();
    // biasable 可偏向模式,默认4S后开启偏向模式
    print("object before", object);
    synchronized (object) {
        // biased 持有偏向锁
        print("object sync", object);
    }
    // biased 偏向锁不会被释放
    print("object after", object);

    Thread t1 = new Thread(() -> {
        synchronized (object) {
            // thin lock 持有轻量级锁,不同线程请求
            print("[t1]object sync", object);
        }
        // non-biasable 不可偏向模式
        print("[t1]object after", object);
    });
    t1.start();
    sleep(100);
    Thread t2 = new Thread(() -> {
        synchronized (object) {
            // thin lock 持有轻量级锁,不同线程请求
            print("[t2]object sync", object);
            sleep(1000);
            // fat lock 重量级锁,下面加锁失败导致
            print("[t2]object sync sleep", object);
        }
    });
    t2.start();
    sleep(500);
    synchronized (object) {
        // fat lock 重量级锁
        print("[main]object sync", object);
    }
    // fat lock 重量级锁不会撤销,线程结束变为不可偏向模式
    print("[main]object after", object);
}

批量重偏向&批量撤销

public static void main(String[] args) throws InterruptedException {
    print("oldPrincipe", new SynchronizedPrincipe());
    int loop = 39;
    List<SynchronizedPrincipe> list = new ArrayList<>();
    for (int i = 0; i < loop; i++) {
        SynchronizedPrincipe principe = new SynchronizedPrincipe();
        list.add(principe);
    }
    for (int thread = 1; thread <= 3; thread++) {
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < list.size(); i++) {
                print(i + 1, list.get(i));
                synchronized (list.get(i)) {
                    // 19: thin lock
                    // 20: biased (Rebias)
                    print(i + 1, list.get(i));
                }
                print(i + 1, list.get(i));
            }
        });
        t1.start();
        sleep(1000);
    }
    SynchronizedPrincipe newPrincipe = new SynchronizedPrincipe();
    // non-biasable (Revoke)
    print("newPrincipe", newPrincipe);
}

参考

  • 关于 Synchronized 的一个点,网上99%的文章都错了
  • 并发系列三:证明分代年龄、无锁、偏向锁、轻量锁、重(chong)偏向、重(chong)轻量、重量锁
举报

相关推荐

iOS底层原理22:KVC底层原理

docker 底层原理

Redis底层原理

ThreadLocal底层原理

SpringBoot底层原理

Zookeeper底层原理

0 条评论