synchronized锁的状态总共有四种,无锁状态、偏向锁、轻量级锁和重量级锁。随着锁的竞争( 无锁 —> 偏向锁 —> 轻量级 —> 重量级锁)
锁可以从偏向锁升级到轻量级锁,再升级的重量级锁,但是锁的升级是单向的,也就是说只能从低到高升级,不会出现锁的降级。
乐观锁:
乐观锁是一种乐观思想,即认为读多写少,遇到并发写的可能性低,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,采取在写时先读出当前版本号,然后加锁操作(比较跟上一次的版本号,如果一样则更新),如果失败则要重复读-比较-写的操作。java中的乐观锁基本都是通过CAS操作实现的,CAS是一种更新的原子操作,比较当前值跟传入值是否一样,一样则更新,否则失败。
悲观锁:
悲观锁是就是悲观思想,即认为写多,遇到并发写的可能性高,每次去拿数据的时候都认为别人会修改,所以每次在读写数据的时候都会上锁,这样别人想读写这个数据就会block直到拿到锁。java中的悲观锁就是Synchronized,AQS框架下的锁则是先尝试cas乐观锁去获取锁,获取不到,才会转换为悲观锁,如RetreenLock。
自旋锁(CAS):
自旋锁就是让不满足条件的线程等待一段时间,而不是立即挂起。看持有锁的线程是否能够很快释放锁。怎么自旋呢?其实就是一段没有任何意义的循环。虽然它通过占用处理器的时间来避免线程切换带来的开销,但是如果持有锁的线程不能在很快释放锁,那么自旋的线程就会浪费处理器的资源,因为它不会做任何有意义的工作。所以,自旋等待的时间或者次数是有一个限度的,如果自旋超过了定义的时间仍然没有获取到锁,则该线程应该被挂起。JDK1.6中-XX:+UseSpinning开启; -XX:PreBlockSpin=10 为自旋次数; JDK1.7后,去掉此参数,由jvm控制;

轻量级锁

轻量级锁的使用场景:如果一个对象虽然有多线程要加锁,但加锁的时间是错开的(也就是没有竞争),那么可以使用轻量级锁来优化。轻量级锁对使用者是透明的,即语法仍然是 synchronized
轻量级锁考虑的是竞争锁对象的线程不多,而且线程持有锁的时间也不长的情景。因为阻塞线程需要CPU从用户态转到内核态,代价较大,如果刚刚阻塞不久这个锁就被释放了,那这个代价就有点得不偿失了,因此这个时候就干脆不阻塞这个线程,让它自旋这等待锁释放
轻量锁的升级时机 : 当关闭偏向锁功能多线程竞争偏向锁会导致偏向锁升级为轻量级锁
线程1获取轻量级锁时会先把锁对象的对象头MarkWord复制一份到线程1的栈帧中创建的用于存储锁记录的空间(Lock Record),然后使用CAS把对象头中的内容替换为线程1存储的锁记录的地址;
如果在线程1复制对象头的同时(在线程1CAS之前),线程2也准备获取锁,复制了对象头到线程2的锁记录空间(Lock Record)中,但是在线程2CAS的时候,发现线程1已经把对象头换了,线程2的CAS失败,那么线程2就尝试使用自旋锁来等待线程1释放锁。但是如果自旋的时间太长也不行,因为自旋是要消耗CPU的,因此自旋的次数是有限制的,如果自旋次数到了线程1还没有释放锁,或者线程1还在执行,线程2还在自旋等待,这时又有一个线程3过来竞争这个锁对象,那么这个时候轻量级锁就会膨胀为重量级锁。重量级锁把除了拥有锁的线程都阻塞,防止CPU空转。

  1. public class LightweightLock {
  2. static final Object obj = new Object();
  3. public static void method1() {
  4. synchronized (obj) {
  5. // 同步块 A
  6. method2();
  7. }
  8. }
  9. public static void method2() {
  10. synchronized (obj) {
  11. // 同步块 B
  12. }
  13. }
  14. }
  1. 创建锁记录(Lock Record)对象,每个线程都的栈帧都会包含一个锁记录的结构,内部可以存储锁定对象的Mark Word

image.png

  1. 让锁记录中 Object reference 指向锁对象,并尝试用 cas 替换 Object 的 Mark Word,将 Mark Word 的值存入锁记录

image.png

  1. 如果 cas 替换成功,对象头中存储了锁记录地址和状态 00 (将recoder地址和markd word互换),表示由该线程给对象加锁,这时图示如下

image.png

  1. 如果 cas 失败,有两种情况
  • 如果是其它线程已经持有了该 Object 的轻量级锁,这时表明有竞争,进入锁膨胀过程(详见锁膨胀)
  • 如果是自己执行了 synchronized 锁重入,那么再添加一条 Lock Record 作为重入的计数

image.png

  1. 当退出 synchronized 代码块(解锁时)如果有取值为 null 的锁记录,表示有重入,这时重置锁记录,表示重入计数减一

image.png

  1. 当退出 synchronized代码块(解锁时)锁记录的值不为 null,这时使用 cas 将 Mark Word 的值恢复给对象头,
  • 成功,则解锁成功
  • 失败,说明轻量级锁进行了锁膨胀或已经升级为重量级锁,进入重量级锁解锁流程

    锁膨胀

    如果在尝试加轻量级锁的过程中,CAS 操作无法成功,这时一种情况就是有其它线程(两个及以上)为此对象加上了轻量级锁(有竞争)且线程经过自旋后仍然没有获取到锁,这时需要进行锁膨胀,将轻量级锁变为重量级锁。 ```java public class LockCoarsening { public static void main(String[] args) {

    1. Coarsening c = new Coarsening();
    2. new Thread(() -> {
    3. c.thread1();
    4. }, "t1").start();
    5. new Thread(() -> {
    6. c.thread2();
    7. }, "t2").start();

    }

}

class Coarsening { public void thread1() { synchronized (this) { log.info(“{}获取到锁”, Thread.currentThread().getName()); sleep(1); log.info(“{}释放锁”, Thread.currentThread().getName()); } }

  1. public void thread2() {
  2. synchronized (this) {
  3. log.info("{}获取到锁", Thread.currentThread().getName());
  4. log.info("{}释放锁", Thread.currentThread().getName());
  5. }
  6. }

}

2021-09-30 09:02:19.191 [t1] INFO com.song.synchronize.Coarsening - t1获取到锁 2021-09-30 09:02:20.204 [t1] INFO com.song.synchronize.Coarsening - t1释放锁 //经过1s后t2才获取到锁 2021-09-30 09:02:20.204 [t2] INFO com.song.synchronize.Coarsening - t2获取到锁 2021-09-30 09:02:20.205 [t2] INFO com.song.synchronize.Coarsening - t2释放锁

  1. 1. `t2`进行轻量级加锁时,`t1`已经对该对象加了轻量级锁
  2. ![image.png](https://cdn.nlark.com/yuque/0/2021/png/22353188/1632964815185-77b60652-8529-4c40-8002-580696aa67b6.png#height=317&id=u9d6d35bd&margin=%5Bobject%20Object%5D&name=image.png&originHeight=633&originWidth=1627&originalType=binary&ratio=1&size=93188&status=done&style=none&width=813.5)
  3. 2. 这时`t2`加轻量级锁失败,进入锁膨胀流程,`t2` Object 对象申请 Monitor 锁,让 Object 指向重量级锁地址,然后自己进入 Monitor EntryList BLOCKED
  4. ![image.png](https://cdn.nlark.com/yuque/0/2021/png/22353188/1632965103749-1e49478e-e121-4055-bd78-415147ba9106.png#height=338&id=u9995f620&margin=%5Bobject%20Object%5D&name=image.png&originHeight=676&originWidth=1788&originalType=binary&ratio=1&size=83468&status=done&style=none&width=894)
  5. 3. `t1`退出同步块解锁时,使用 cas Mark Word 的值恢复给对象头,失败。这时会进入重量级解锁流程,即按照 Monitor 地址找到 Monitor 对象,设置 Owner null,唤醒 EntryList BLOCKED 线程
  6. <a name="pvnAB"></a>
  7. # 偏向锁
  8. 偏向锁是一种针对加锁操作的优化手段,它的意思是这个锁会偏向于第一个获得它的线程,如果在接下来的执行过程中,该锁没有被其他的线程获取,则持有偏向锁的线程将永远不需要再进行同步。因为在大多数情况下,锁不仅不存在多线程竞争,而且总是由同一线程多次获得,因此为了减少同一线程获取锁(会涉及到一些CAS操作,耗时)的代价而引入偏向锁。<br />偏向锁的核心思想是,如果一个线程获得了锁,那么锁就进入偏向模式,此时Mark Word 的结构也变为偏向锁结构,当这个线程再次请求锁时,无需再做任何同步操作,即获取锁的过程,对于没有锁竞争的场合,偏向锁有很好的优化效果,但是对于锁竞争比较激烈的场合,偏向锁就失效了,偏向锁失败后,并不会立即膨胀为重量级锁,而是先升级为轻量级锁。简而言之,轻量级锁在没有竞争时只有一个线程使用,每次重入仍然需要执行 CAS 操作。Java 6 中引入了偏向锁来做进一步优化:只有第一次使用 CAS 将线程 ID 设置到对象的 `Mark Word` 头,之后发现这个线程 ID 是自己的就表示没有竞争,不用重新 CAS。以后只要不发生竞争,这个对象就归该线程所有。<br />**偏向锁的目的是消除数据在无竞争情况下的CAS操作,进一步提高程序的运行性能。偏向锁可以通过参数**`-XX:+UseBiasedLocking`**控制偏向锁是否启用。**
  9. ```java
  10. public class BiasedLock {
  11. static final Object obj = new Object();
  12. /**
  13. * 需要使用-XX:BiasedLockingStartupDelay=0参数关闭偏向锁延时
  14. *
  15. * @param args
  16. * @throws InterruptedException
  17. */
  18. public static void main(String[] args) throws InterruptedException {
  19. BiasedLock ll = new BiasedLock();
  20. Thread t1 = new Thread(() -> {
  21. ll.method1();
  22. }, "t1");
  23. t1.start();
  24. t1.join();
  25. }
  26. public void method1() {
  27. synchronized (obj) {
  28. log.info("进入method1,obj {}", ClassLayout.parseInstance(obj).toPrintableSimple());
  29. method2();
  30. }
  31. }
  32. public void method2() {
  33. synchronized (obj) {
  34. log.info("进入method2,obj {}", ClassLayout.parseInstance(obj).toPrintableSimple());
  35. method3();
  36. }
  37. }
  38. public void method3() {
  39. synchronized (obj) {
  40. log.info("进入method3,obj {}", ClassLayout.parseInstance(obj).toPrintableSimple());
  41. }
  42. }

image.png
一个对象创建时如果开启了偏向锁(默认开启),那么对象创建后,markword值为 0x05 即最后 3 位为 101,这时它的threadepochage都为0偏向锁是默认是延迟的(参考markd work头),不会在程序启动时立即生效,如果想避免延迟,可以加 VM 参数-XX:BiasedLockingStartupDelay=0 来禁用延迟,如果没有开启偏向锁,那么对象创建后,markword值为 0x01 即最后 3 位为 001,这时它的 hashcodeage都为 0,第一次用到 hashcode时才会赋值 。

测试偏向锁

利用 jol 第三方工具来查看对象头信息 ,为使输出信息更简洁,重写了其中的 ClassLayout._parseInstance_(obj).toPrintableSimple()方法

  1. <dependency>
  2. <groupId>org.openjdk.jol</groupId>
  3. <artifactId>jol-core</artifactId>
  4. <version>0.16</version>
  5. </dependency>
  1. /**
  2. * 处于偏向锁的对象解锁后,线程 id 仍存储于对象头中
  3. **/
  4. public static void test() throws InterruptedException {
  5. Object obj = new Object();
  6. log.info("进入synchronized前 {}", ClassLayout.parseInstance(obj).toPrintableSimple());
  7. Thread t1 = new Thread(() -> {
  8. synchronized (obj) {
  9. log.info("进入synchronized {}", ClassLayout.parseInstance(obj).toPrintableSimple());
  10. }
  11. }, "t1");
  12. t1.start();
  13. t1.join();
  14. log.info("进入synchronized后 {}", ClassLayout.parseInstance(obj).toPrintableSimple());
  15. }
  16. 2021-09-30 14:40:37.127 [main] INFO - 进入synchronized
  17. (object header: mark) 00000000 00000000 00000000 00000101 (biasable; age: 0)
  18. 2021-09-30 14:40:37.131 [t1] INFO - 进入synchronized
  19. (object header: mark) 00100110 00011011 11100000 00000101 (biased: 0x000000008e4986f8; epoch: 0; age: 0)
  20. 2021-09-30 14:40:37.131 [main] INFO - 进入synchronized
  21. (object header: mark) 00100110 00011011 11100000 00000101 (biased: 0x000000008e4986f8; epoch: 0; age: 0)

禁用偏向锁

在上面测试代码运行时在添加 VM 参数-XX:-UseBiasedLocking禁用偏向锁
输出

  1. 2021-09-30 14:43:17.588 [main] INFO - 进入synchronized未加锁状态
  2. (object header: mark) 00000000 00000000 00000000 00000001 (non-biasable; age: 0)
  3. 2021-09-30 14:43:17.591 [t1] INFO - 进入synchronized轻量级锁状态
  4. (object header: mark) 11101100 10101111 11110100 01110000 (thin lock: 0x00000016ecaff470)
  5. 2021-09-30 14:43:17.591 [main] INFO - 进入synchronized后解除加锁状态
  6. (object header: mark) 00000000 00000000 00000000 00000001 (non-biasable; age: 0)

撤销偏向锁

调用HashCode方法后偏向锁被撤销

调用了对象的 hashCode,偏向锁的对象 MarkWord 中存储的是线程 id,如果调用 hashCode 会导致偏向锁被撤销,轻量级锁会在锁记录中记录 hashCode,重量级锁会在 Monitor 中记录 hashCode。

  1. public static void test() throws InterruptedException {
  2. Object obj = new Object();
  3. log.info("进入synchronized\n {}", ClassLayout.parseInstance(obj).toPrintableSimple());
  4. Thread t1 = new Thread(() -> {
  5. obj.hashCode();
  6. log.info("hascode之后\n {}", ClassLayout.parseInstance(obj).toPrintableSimple());
  7. synchronized (obj) {
  8. log.info("进入synchronized\n {}", ClassLayout.parseInstance(obj).toPrintableSimple());
  9. }
  10. }, "t1");
  11. t1.start();
  12. t1.join();
  13. log.info("进入synchronized后\n {}", ClassLayout.parseInstance(obj).toPrintableSimple());
  14. }
  15. 2021-09-30 14:47:58.067 [main] INFO - 进入synchronized 无锁状态
  16. (object header: mark) 00000000 00000000 00000000 00000001 (non-biasable; age: 0)
  17. 2021-09-30 14:47:58.070 [t1] INFO - hascode之后 无锁状态但是markword存储了hashcode信息
  18. (object header: mark) 00111010 11101000 11011001 00000001 (hash: 0x683ae8d9; age: 0)
  19. 2021-09-30 14:47:58.071 [t1] INFO - 进入synchronized 轻量级锁,hashcode被替换为线程id
  20. (object header: mark) 11100101 10111111 11110000 01110000 (thin lock: 0x00000035e5bff070)
  21. 2021-09-30 14:47:58.071 [main] INFO - 进入synchronized 无锁状态,markword存储了hashcode
  22. (object header: mark) 00111010 11101000 11011001 00000001 (hash: 0x683ae8d9; age: 0)

有其他线程竞争同一把锁(错开竞争)

  1. public static void main(String[] args) throws InterruptedException {
  2. BiasedLock ll = new BiasedLock();
  3. Thread t1 = new Thread(() -> {
  4. ll.method1();
  5. }, "t1");
  6. Thread t2 = new Thread(() -> {
  7. ll.method1();
  8. }, "t2");
  9. t1.start();
  10. t1.join();
  11. t2.start();
  12. t2.join();
  13. log.info("进入main,obj {}", ClassLayout.parseInstance(obj).toPrintableSimple());
  14. }
  15. //起出只有线程1使用锁,所以是偏向锁
  16. 2021-09-30 14:53:39.916 [t1] INFO - 进入method1,obj (object header: mark)
  17. 00010111 00100001 00111000 00000101 (biased: 0x000000008105c84e; epoch: 0; age: 0)
  18. 2021-09-30 14:53:39.919 [t1] INFO - 进入method2,obj (object header: mark)
  19. 00010111 00100001 00111000 00000101 (biased: 0x000000008105c84e; epoch: 0; age: 0)
  20. 2021-09-30 14:53:39.919 [t1] INFO - 进入method3,obj (object header: mark)
  21. 00010111 00100001 00111000 00000101 (biased: 0x000000008105c84e; epoch: 0; age: 0)
  22. //线程2 将线程1的偏向锁升级为轻量级锁
  23. 2021-09-30 14:53:39.920 [t2] INFO - 进入method1,obj (object header: mark)
  24. 11000101 00011111 11101101 10111000 (thin lock: 0x000000bdc51fedb8)
  25. 2021-09-30 14:53:39.920 [t2] INFO - 进入method2,obj (object header: mark)
  26. 11000101 00011111 11101101 10111000 (thin lock: 0x000000bdc51fedb8)
  27. 2021-09-30 14:53:39.921 [t2] INFO - 进入method3,obj (object header: mark)
  28. 11000101 00011111 11101101 10111000 (thin lock: 0x000000bdc51fedb8)
  29. //释放后变为无锁
  30. 2021-09-30 14:53:39.921 [main] INFO - 进入main,obj (object header: mark)
  31. 00000000 00000000 00000000 00000001 (non-biasable; age: 0)

使用wait/notify

  1. /**
  2. * 测试wait / notify对偏向锁的影响
  3. *
  4. * @throws InterruptedException
  5. */
  6. public static void testWait() {
  7. Object obj = new Object();
  8. log.info("进入synchronized\n {}", ClassLayout.parseInstance(obj).toPrintableSimple());
  9. new Thread(() -> {
  10. synchronized (obj) {
  11. try {
  12. log.info("wait前\n {}", ClassLayout.parseInstance(obj).toPrintableSimple());
  13. obj.wait();
  14. log.info("notify后\n {}", ClassLayout.parseInstance(obj).toPrintableSimple());
  15. } catch (InterruptedException e) {
  16. e.printStackTrace();
  17. }
  18. }
  19. synchronized (BiasedLock.class) {
  20. BiasedLock.class.notify();
  21. }
  22. }, "t1").start();
  23. new Thread(() -> {
  24. Sleeper.sleep(2);
  25. synchronized (obj) {
  26. log.info("notify前\n {}", ClassLayout.parseInstance(obj).toPrintableSimple());
  27. obj.notify();
  28. }
  29. }, "t2").start();
  30. Sleeper.sleep(3);
  31. log.info("主线程\n {}", ClassLayout.parseInstance(obj).toPrintableSimple());
  32. }
  33. 2021-09-30 15:13:48.691 [main] INFO - 进入synchronized 偏向锁可用
  34. (object header: mark) 00000000 00000000 00000000 00000101 (biasable; age: 0)
  35. 2021-09-30 15:13:48.695 [t1] INFO - wait t1的偏向锁
  36. (object header: mark) 00100101 01110101 00101000 00000101 (biased: 0x000000006cc95d4a; epoch: 0; age: 0)
  37. 2021-09-30 15:13:50.701 [t2] INFO - notify 升级为重量级锁
  38. (object header: mark) 00100010 11101100 01001110 11101010 (fat lock: 0x000001b322ec4eea)
  39. 2021-09-30 15:13:50.702 [t1] INFO - notify 撤销偏向锁改为重量级锁
  40. (object header: mark) 01111111 00100010 01001111 01001010 (fat lock: 0x0000010c7f224f4a)
  41. 2021-09-30 15:13:51.710 [main] INFO - 主线程 释放锁撤销偏向锁
  42. (object header: mark) 00000000 00000000 00000000 00000001 (non-biasable; age: 0)

批量重偏向

如果对象虽然被多个线程访问,但没有竞争,这时偏向了线程 T1 的对象仍有机会重新偏向 T2,重偏向会重置对象的 Thread ID当撤销偏向锁阈值超过 20 次后,jvm 会这样觉得,我是不是偏向错了呢,于是会在给这些对象加锁时重新偏向至加锁线程
**-XX:BiasedLockingBulkRebiasThreshold=20 ** 默认偏向锁批量重偏向阈值

     /**
     * 测试批量重偏向
     */
     public static void testBatchBiased() {

        List<Object> list = new Vector<>();
        new Thread(() -> {
            for (int i = 0; i < 30; i++) {
                Object obj = new Object();
                synchronized (obj) {
                    list.add(obj);
                    log.info("{}   {}", i + 1, ClassLayout.parseInstance(obj).toPrintableSimple());
                }
            }
            synchronized (list) {
                list.notify();
            }
        }, "t1").start();
        new Thread(() -> {
            synchronized (list) {
                try {
                    list.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            for (int i = 0; i < list.size(); i++) {
                Object obj = list.get(i);
                log.info("{}加锁前{}", i + 1, ClassLayout.parseInstance(obj).toPrintableSimple());
                synchronized (obj) {
                    log.info("{}   {}", i + 1, ClassLayout.parseInstance(obj).toPrintableSimple());
                }
                log.info("{}加锁后{}", i + 1, ClassLayout.parseInstance(obj).toPrintableSimple());
            }
        }, "t2").start();
    }

输出结果

2021-09-30 16:09:59.370 [t1] INFO - 1    00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.374 [t1] INFO - 2    00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.374 [t1] INFO - 3    00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.374 [t1] INFO - 4    00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.374 [t1] INFO - 5    00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.374 [t1] INFO - 6    00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.374 [t1] INFO - 7    00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.374 [t1] INFO - 8    00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.374 [t1] INFO - 9    00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.375 [t1] INFO - 10    00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.375 [t1] INFO - 11    00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.375 [t1] INFO - 12    00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.375 [t1] INFO - 13    00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.375 [t1] INFO - 14    00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.375 [t1] INFO - 15    00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.375 [t1] INFO - 16    00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.375 [t1] INFO - 17    00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.376 [t1] INFO - 18    00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.376 [t1] INFO - 19    00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.376 [t1] INFO - 20    00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.376 [t1] INFO - 21    00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.376 [t1] INFO - 22    00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.376 [t1] INFO - 23    00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.376 [t1] INFO - 24    00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.376 [t1] INFO - 25    00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.377 [t1] INFO - 26    00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.377 [t1] INFO - 27    00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.377 [t1] INFO - 28    00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.377 [t1] INFO - 29    00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.377 [t1] INFO - 30    00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.377 [t2] INFO - 1加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.377 [t2] INFO - 1    00000000 00000000 00000000 10111101 10101010 11101111 11110100 00000000 (thin lock: 0x000000bdaaeff400)
2021-09-30 16:09:59.378 [t2] INFO - 1加锁后 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 (non-biasable; age: 0)
2021-09-30 16:09:59.378 [t2] INFO - 2加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.378 [t2] INFO - 2    00000000 00000000 00000000 10111101 10101010 11101111 11110100 00000000 (thin lock: 0x000000bdaaeff400)
2021-09-30 16:09:59.378 [t2] INFO - 2加锁后 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 (non-biasable; age: 0)
2021-09-30 16:09:59.378 [t2] INFO - 3加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.378 [t2] INFO - 3    00000000 00000000 00000000 10111101 10101010 11101111 11110100 00000000 (thin lock: 0x000000bdaaeff400)
2021-09-30 16:09:59.378 [t2] INFO - 3加锁后 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 (non-biasable; age: 0)
2021-09-30 16:09:59.379 [t2] INFO - 4加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.379 [t2] INFO - 4    00000000 00000000 00000000 10111101 10101010 11101111 11110100 00000000 (thin lock: 0x000000bdaaeff400)
2021-09-30 16:09:59.379 [t2] INFO - 4加锁后 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 (non-biasable; age: 0)
2021-09-30 16:09:59.379 [t2] INFO - 5加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.379 [t2] INFO - 5    00000000 00000000 00000000 10111101 10101010 11101111 11110100 00000000 (thin lock: 0x000000bdaaeff400)
2021-09-30 16:09:59.379 [t2] INFO - 5加锁后 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 (non-biasable; age: 0)
2021-09-30 16:09:59.379 [t2] INFO - 6加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.379 [t2] INFO - 6    00000000 00000000 00000000 10111101 10101010 11101111 11110100 00000000 (thin lock: 0x000000bdaaeff400)
2021-09-30 16:09:59.379 [t2] INFO - 6加锁后 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 (non-biasable; age: 0)
2021-09-30 16:09:59.380 [t2] INFO - 7加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.380 [t2] INFO - 7    00000000 00000000 00000000 10111101 10101010 11101111 11110100 00000000 (thin lock: 0x000000bdaaeff400)
2021-09-30 16:09:59.380 [t2] INFO - 7加锁后 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 (non-biasable; age: 0)
2021-09-30 16:09:59.380 [t2] INFO - 8加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.380 [t2] INFO - 8    00000000 00000000 00000000 10111101 10101010 11101111 11110100 00000000 (thin lock: 0x000000bdaaeff400)
2021-09-30 16:09:59.380 [t2] INFO - 8加锁后 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 (non-biasable; age: 0)
2021-09-30 16:09:59.380 [t2] INFO - 9加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.380 [t2] INFO - 9    00000000 00000000 00000000 10111101 10101010 11101111 11110100 00000000 (thin lock: 0x000000bdaaeff400)
2021-09-30 16:09:59.381 [t2] INFO - 9加锁后 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 (non-biasable; age: 0)
2021-09-30 16:09:59.381 [t2] INFO - 10加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.381 [t2] INFO - 10    00000000 00000000 00000000 10111101 10101010 11101111 11110100 00000000 (thin lock: 0x000000bdaaeff400)
2021-09-30 16:09:59.381 [t2] INFO - 10加锁后 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 (non-biasable; age: 0)
2021-09-30 16:09:59.381 [t2] INFO - 11加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.381 [t2] INFO - 11    00000000 00000000 00000000 10111101 10101010 11101111 11110100 00000000 (thin lock: 0x000000bdaaeff400)
2021-09-30 16:09:59.381 [t2] INFO - 11加锁后 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 (non-biasable; age: 0)
2021-09-30 16:09:59.381 [t2] INFO - 12加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.382 [t2] INFO - 12    00000000 00000000 00000000 10111101 10101010 11101111 11110100 00000000 (thin lock: 0x000000bdaaeff400)
2021-09-30 16:09:59.382 [t2] INFO - 12加锁后 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 (non-biasable; age: 0)
2021-09-30 16:09:59.382 [t2] INFO - 13加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.382 [t2] INFO - 13    00000000 00000000 00000000 10111101 10101010 11101111 11110100 00000000 (thin lock: 0x000000bdaaeff400)
2021-09-30 16:09:59.382 [t2] INFO - 13加锁后 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 (non-biasable; age: 0)
2021-09-30 16:09:59.382 [t2] INFO - 14加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.382 [t2] INFO - 14    00000000 00000000 00000000 10111101 10101010 11101111 11110100 00000000 (thin lock: 0x000000bdaaeff400)
2021-09-30 16:09:59.382 [t2] INFO - 14加锁后 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 (non-biasable; age: 0)
2021-09-30 16:09:59.383 [t2] INFO - 15加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.383 [t2] INFO - 15    00000000 00000000 00000000 10111101 10101010 11101111 11110100 00000000 (thin lock: 0x000000bdaaeff400)
2021-09-30 16:09:59.383 [t2] INFO - 15加锁后 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 (non-biasable; age: 0)
2021-09-30 16:09:59.383 [t2] INFO - 16加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.383 [t2] INFO - 16    00000000 00000000 00000000 10111101 10101010 11101111 11110100 00000000 (thin lock: 0x000000bdaaeff400)
2021-09-30 16:09:59.383 [t2] INFO - 16加锁后 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 (non-biasable; age: 0)
2021-09-30 16:09:59.383 [t2] INFO - 17加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.383 [t2] INFO - 17    00000000 00000000 00000000 10111101 10101010 11101111 11110100 00000000 (thin lock: 0x000000bdaaeff400)
2021-09-30 16:09:59.384 [t2] INFO - 17加锁后 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 (non-biasable; age: 0)
2021-09-30 16:09:59.384 [t2] INFO - 18加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.384 [t2] INFO - 18    00000000 00000000 00000000 10111101 10101010 11101111 11110100 00000000 (thin lock: 0x000000bdaaeff400)
2021-09-30 16:09:59.384 [t2] INFO - 18加锁后 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 (non-biasable; age: 0)
2021-09-30 16:09:59.384 [t2] INFO - 19加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.384 [t2] INFO - 19    00000000 00000000 00000010 00100111 00101000 00110000 00100001 00000101 (biased: 0x0000000089ca0c08; epoch: 0; age: 0)
2021-09-30 16:09:59.384 [t2] INFO - 19加锁后 00000000 00000000 00000010 00100111 00101000 00110000 00100001 00000101 (biased: 0x0000000089ca0c08; epoch: 0; age: 0)
2021-09-30 16:09:59.385 [t2] INFO - 20加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.385 [t2] INFO - 20    00000000 00000000 00000010 00100111 00101000 00110000 00100001 00000101 (biased: 0x0000000089ca0c08; epoch: 0; age: 0)
2021-09-30 16:09:59.385 [t2] INFO - 20加锁后 00000000 00000000 00000010 00100111 00101000 00110000 00100001 00000101 (biased: 0x0000000089ca0c08; epoch: 0; age: 0)
2021-09-30 16:09:59.385 [t2] INFO - 21加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.385 [t2] INFO - 21    00000000 00000000 00000010 00100111 00101000 00110000 00100001 00000101 (biased: 0x0000000089ca0c08; epoch: 0; age: 0)
2021-09-30 16:09:59.385 [t2] INFO - 21加锁后 00000000 00000000 00000010 00100111 00101000 00110000 00100001 00000101 (biased: 0x0000000089ca0c08; epoch: 0; age: 0)
2021-09-30 16:09:59.385 [t2] INFO - 22加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.386 [t2] INFO - 22    00000000 00000000 00000010 00100111 00101000 00110000 00100001 00000101 (biased: 0x0000000089ca0c08; epoch: 0; age: 0)
2021-09-30 16:09:59.386 [t2] INFO - 22加锁后 00000000 00000000 00000010 00100111 00101000 00110000 00100001 00000101 (biased: 0x0000000089ca0c08; epoch: 0; age: 0)
2021-09-30 16:09:59.386 [t2] INFO - 23加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.386 [t2] INFO - 23    00000000 00000000 00000010 00100111 00101000 00110000 00100001 00000101 (biased: 0x0000000089ca0c08; epoch: 0; age: 0)
2021-09-30 16:09:59.386 [t2] INFO - 23加锁后 00000000 00000000 00000010 00100111 00101000 00110000 00100001 00000101 (biased: 0x0000000089ca0c08; epoch: 0; age: 0)
2021-09-30 16:09:59.386 [t2] INFO - 24加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.386 [t2] INFO - 24    00000000 00000000 00000010 00100111 00101000 00110000 00100001 00000101 (biased: 0x0000000089ca0c08; epoch: 0; age: 0)
2021-09-30 16:09:59.387 [t2] INFO - 24加锁后 00000000 00000000 00000010 00100111 00101000 00110000 00100001 00000101 (biased: 0x0000000089ca0c08; epoch: 0; age: 0)
2021-09-30 16:09:59.387 [t2] INFO - 25加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.387 [t2] INFO - 25    00000000 00000000 00000010 00100111 00101000 00110000 00100001 00000101 (biased: 0x0000000089ca0c08; epoch: 0; age: 0)
2021-09-30 16:09:59.387 [t2] INFO - 25加锁后 00000000 00000000 00000010 00100111 00101000 00110000 00100001 00000101 (biased: 0x0000000089ca0c08; epoch: 0; age: 0)
2021-09-30 16:09:59.387 [t2] INFO - 26加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.387 [t2] INFO - 26    00000000 00000000 00000010 00100111 00101000 00110000 00100001 00000101 (biased: 0x0000000089ca0c08; epoch: 0; age: 0)
2021-09-30 16:09:59.387 [t2] INFO - 26加锁后 00000000 00000000 00000010 00100111 00101000 00110000 00100001 00000101 (biased: 0x0000000089ca0c08; epoch: 0; age: 0)
2021-09-30 16:09:59.388 [t2] INFO - 27加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.388 [t2] INFO - 27    00000000 00000000 00000010 00100111 00101000 00110000 00100001 00000101 (biased: 0x0000000089ca0c08; epoch: 0; age: 0)
2021-09-30 16:09:59.388 [t2] INFO - 27加锁后 00000000 00000000 00000010 00100111 00101000 00110000 00100001 00000101 (biased: 0x0000000089ca0c08; epoch: 0; age: 0)
2021-09-30 16:09:59.388 [t2] INFO - 28加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.388 [t2] INFO - 28    00000000 00000000 00000010 00100111 00101000 00110000 00100001 00000101 (biased: 0x0000000089ca0c08; epoch: 0; age: 0)
2021-09-30 16:09:59.388 [t2] INFO - 28加锁后 00000000 00000000 00000010 00100111 00101000 00110000 00100001 00000101 (biased: 0x0000000089ca0c08; epoch: 0; age: 0)
2021-09-30 16:09:59.388 [t2] INFO - 29加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.388 [t2] INFO - 29    00000000 00000000 00000010 00100111 00101000 00110000 00100001 00000101 (biased: 0x0000000089ca0c08; epoch: 0; age: 0)
2021-09-30 16:09:59.389 [t2] INFO - 29加锁后 00000000 00000000 00000010 00100111 00101000 00110000 00100001 00000101 (biased: 0x0000000089ca0c08; epoch: 0; age: 0)
2021-09-30 16:09:59.389 [t2] INFO - 30加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.389 [t2] INFO - 30    00000000 00000000 00000010 00100111 00101000 00110000 00100001 00000101 (biased: 0x0000000089ca0c08; epoch: 0; age: 0)
2021-09-30 16:09:59.389 [t2] INFO - 30加锁后 00000000 00000000 00000010 00100111 00101000 00110000 00100001 00000101 (biased: 0x0000000089ca0c08; epoch: 0; age: 0)

分析结果:
t1线程经过30次的迭代后将30个obj对象变成了偏向t1线程的锁,t1结束运行,t2开始执行,在前18次加锁的时候都是将偏向锁重置为无锁,第19次开始,开始将锁重置为t2线程的偏向锁(线程id改变了)

批量撤销

当撤销偏向锁阈值超过 40 次后,jvm 会这样觉得,自己确实偏向错了,根本就不该偏向。于是整个类的所有对象都会变为不可偏向的,新建的对象也是不可偏向的 ,偏向锁的撤销实际上指的是将偏向锁变成轻量级锁的过程,.
-XX:BiasedLockingBulkRevokeThreshold=40 默认偏向锁批量撤销阈值

  1. 批量重偏向和批量撤销是针对类的优化,和对象无关。
  2. 偏向锁重偏向一次之后不可再次重偏向。
  3. 当某个类已经触发批量撤销机制后,JVM会默认当前类产生了严重的问题,剥夺了该类的新实例对象使用偏向锁的权利

    /**
      * 测试批量撤销偏向锁
      */
     public static void testBatchCancle() throws InterruptedException {
         List<Dog> list = new Vector<>();
         //线程1添加偏向锁
         int loopNumber = 39;
         t1 = new Thread(() -> {
             for (int i = 0; i < loopNumber; i++) {
                 Dog o = new Dog();
                 list.add(o);
                 synchronized (o) {
                     log.info("{}   {}", i + 1, ClassLayout.parseInstance(o).toPrintableSimple());
                 }
             }
             //唤醒t2线程
             LockSupport.unpark(t2);
         }, "t1");
         t2 = new Thread(() -> {
             //t2阻塞,等待t1执行完
             LockSupport.park();
             for (int i = 0; i < loopNumber; i++) {
                 Dog o = list.get(i);
                 synchronized (o) {
                     log.info("{}   {}", i + 1, ClassLayout.parseInstance(o).toPrintableSimple());
                 }
             }
             LockSupport.unpark(t3);
         }, "t2");
         t3 = new Thread(() -> {
             //t3阻塞,等待t2执行完
             LockSupport.park();
             for (int i = 0; i < loopNumber; i++) {
                 Dog o = list.get(i);
                 synchronized (o) {
                     log.info("{}   {}", i + 1, ClassLayout.parseInstance(o).toPrintableSimple());
                 }
             }
         }, "t3");
         t1.start();
         t2.start();
         t3.start();
         t3.join();
         Dog o = new Dog();
         log.info(" {}", ClassLayout.parseInstance(o).toPrintableSimple());
     }
    

    锁消除

    锁消除即删除不必要的加锁操作。JVM在运行时,对一些在代码上要求同步,但是被检测到不可能存在共享数据竞争情况的锁进行消除。根据代码逃逸技术,如果判断到一段代码中,堆上的数据不会逃逸出当前线程,那么就可以认为这段代码是线程安全的,无需加锁。

    static int x = 0;
    public void a() throws Exception {
     x++;
    }
    public void b() throws Exception {
     //对象o没有发生逃逸      
     Object o = new Object();
     synchronized (o) {
         x++;
     }
    }
    

    逃逸分析

    在编程语言的编译优化原理中,分析指针动态范围的方法称之为逃逸分析。通俗一点讲,当一个对象的指针被多个方法或线程引用时,我们称这个指针发生了逃逸。JVM判断新创建的对象是否逃逸的依据有两个:

  4. 对象被赋值给堆中对象的字段或者类的静态变量

  5. 对象被传进了不确定的代码中去运行
  • 方法逃逸

一个对象在方法中被定义,但却被方法以外的其他代码使用。如传参到其他方法中等可能导致此情况发生。

  • 线程逃逸
    一个对象由某个线程在方法中被定义,但却被其他线程访问。如类变量、公用的或有get、set方法的实例变量等
  • 逃逸分析具体配置
    • 开启逃逸分析(JDK8中,逃逸分析默认开启。)
      -XX:+DoEscapeAnalysis
    • 关闭逃逸分析
      -XX:-DoEscapeAnalysis
    • 逃逸分析结果展示
      -XX:+PrintEscapeAnalysis
  • 案例 ```java public class EscapeTest {

    public static Object globalVariableObject;

    public Object instanceObject;

    public void globalVariableEscape(){

      globalVariableObject = new Object(); // 静态变量,外部线程可见,发生逃逸
    

    }

    public void instanceObjectEscape(){

      instanceObject = new Object(); // 赋值给堆中实例字段,外部线程可见,发生逃逸
    

    }

    public Object returnObjectEscape(){

      return new Object();  // 返回实例,外部线程可见,发生逃逸
    

    }

    public void noEscape(){

      Object noEscape = new Object();  // 仅创建线程可见,对象无逃逸
    

    }

}

<a name="SZVuE"></a>
# 锁粗化
一个程序对同一个锁不间断、高频地请求、同步与释放,会消耗掉一定的系统资源,这样高频的锁请求就不利于系统性能的优化了。**锁粗化就是把很多次锁的请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗。**<br />一种极端的情况如下:
```java
public void doSomethingMethod(){
    synchronized(lock){
        //do some thing
    }
    //这是还有一些代码,做其它不需要同步的工作,但能很快执行完毕
    synchronized(lock){
        //do other thing
    }
}

上面的代码是有两块需要同步操作的,但在这两块需要同步操作的代码之间,需要做一些其它的工作,而这些工作只会花费很少的时间,那么我们就可以把这些工作代码放入锁内,将两个同步代码块合并成一个,以降低多次锁请求、同步、释放带来的系统性能消耗,合并后的代码如下:

public void doSomethingMethod(){
    //进行锁粗化:整合成一次锁请求、同步、释放
    synchronized(lock){
        //do some thing
        //做其它不需要同步但能很快执行完的工作
        //do other thing
    }
}

注意:这样做是有前提的,就是中间不需要同步的代码能够很快速地完成,如果不需要同步的代码需要花很长时间,就会导致同步块的执行需要花费很长的时间,这样做也就不合理了。
另一种需要锁粗化的极端的情况是:

for(int i=0;i<size;i++){
    synchronized(lock){
    }
}

上面代码每次循环都会进行锁的请求、同步与释放,看起来貌似没什么问题,且在jdk内部会对这类代码锁的请求做一些优化,但是还不如把加锁代码写在循环体的外面,这样一次锁的请求就可以达到我们的要求,除非有特殊的需要:循环需要花很长时间,但其它线程等不起,要给它们执行的机会。

synchronized(lock){
    for(int i=0;i<size;i++){
    }
}

重量级锁

重量级锁通过对象内部的监视器(monitor)实现,其中monitor的本质是依赖于底层操作系统的Mutex Lock实现,操作系统实现线程之间的切换需要从用户态到内核态的切换,切换成本非常高。主要是,当系统检查到锁是重量级锁之后,会把等待想要获得锁的线程进行阻塞,被阻塞的线程不会消耗cup。但是阻塞或者唤醒一个线程时,都需要操作系统来帮忙,这就需要从用户态转换到内核态,而转换状态是需要消耗很多时间的,有可能比用户执行代码的时间还要长。这就是说为什么重量级线程开销很大的。