一探究竟:反编译
三种使用场景,示例代码;
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对象由三个部分组成;
- 对象头:对象年龄,锁标志,Class类型指针和数组长度(可选);
 - 实例数据:真正存储的有效数据,例如当前的成员变量,包括父类;
 - 对齐填充: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)轻量、重量锁
 









