0%

java-lock

1. 锁优化

2. jvm 的锁优化

  • 偏向锁

偏向锁是一种针对加锁操作的优化.
它的核心思想是: 如果一个线程获得了锁, 那么锁就进入了偏向模式; 当这个线程再次请求这个锁的时候, 无须再做任何同步操作.
这样就节省了大量有关锁申请的操作, 从而提高性能.
对于没有锁竞争的场合, 偏向锁有比较好的优化效果, 因为连续多次极有可能是同一个线程请求相同的锁; 而对于锁竞争比较激烈的场景, 很可能每次都是不同的线程来请求同一把锁, 偏向模式就会失效, 导致其效果不佳.

可以使用 -XX:+UseBiasedLocking 参数打开偏向锁.

  • 轻量级锁

如果偏向锁失败, 虚拟机并不会立即挂起线程, 它还会使用一种称为轻量级锁的优化手段.
轻量级锁的操作也很轻便, 它只是简单的将对象头部作为指针, 指向持有锁的线程堆栈的内部, 来判断一个线程是否持有对象锁.
如果线程获得轻量级锁成功, 则可以顺利进入临界区; 如果轻量级锁加锁失败, 则表示其他线程抢先争夺到了锁, 那么当前线程的锁请求就会膨胀为重量级锁.

  • 自旋锁

锁膨胀后, 虚拟机威廉避免线程真实地在操作系统层面挂起, 虚拟机还会在做最后的努力 – 自旋锁.
由于当前线程暂时无法获得锁, 什么时候可以获得锁是一个未知数. 也许在几个 CPU 时钟周期后, 就可以得到锁. 如果就这样简单粗暴地挂起线程可能是一种得不偿失的操作.
因此, 系统会进行一次赌注: 假设线程会在不久的将来等到锁, 所以虚拟机会让当前线程做几个空循环 (这也就是自旋). 如果线程在经过若干次循环之后得到锁, 那么就顺利进入临界区; 如果还是不能获得锁, 才会真实地将线程在操作系统层面挂起.

可以使用 -XX:+UseSpinning 参数打开自旋锁, 默认开启.
可以使用 -XX:PreBlockSpin 来设置自旋次数, 默认 10 次.

  • 锁消除

锁消除是一种更彻底的锁优化.
Java 虚拟机在 JIT 编译时, 通过运行上下文的扫描, 去除不可能存在共享资源竞争的锁.
通过锁消除可以节省毫无意义的请求锁时间.

比如实例方法内部的 Vector, StringBuffer 等. 像 Vector 内部是使用 synchronized 请求锁, 但是在实例方法内部的局部变量是不可能存在锁竞争的, 所以 Vector 内部的加锁同步就会变得毫无必要.

锁消除设计的一项关键技术为逃逸分析. 所谓逃逸分析就是观察某个变量是否会逃出某一个作用域.
逃逸分析必须在 -server 模式下进行, 可以使用 -XX:+DoEscapeAnalysis 参数打开逃逸分析;
然后使用 -XX:+EliminateLocks 参数打开锁消除.

3. Resource

  • Java 高并发程序设计
  • 深入了解 Java 虚拟机